mirror of
https://github.com/correl/mage.git
synced 2024-12-28 03:00:10 +00:00
Merge pull request #43 from magefree/master
Merge https://github.com/magefree/mage
This commit is contained in:
commit
0a1ae58943
51 changed files with 1437 additions and 378 deletions
|
@ -28,6 +28,7 @@
|
||||||
package mage.server;
|
package mage.server;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.Map.Entry;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
import java.util.concurrent.locks.ReadWriteLock;
|
import java.util.concurrent.locks.ReadWriteLock;
|
||||||
|
@ -37,6 +38,8 @@ import java.util.regex.Pattern;
|
||||||
import mage.cards.repository.CardInfo;
|
import mage.cards.repository.CardInfo;
|
||||||
import mage.cards.repository.CardRepository;
|
import mage.cards.repository.CardRepository;
|
||||||
import mage.server.exceptions.UserNotFoundException;
|
import mage.server.exceptions.UserNotFoundException;
|
||||||
|
import mage.server.game.GameController;
|
||||||
|
import mage.server.game.GameManager;
|
||||||
import mage.server.util.SystemUtil;
|
import mage.server.util.SystemUtil;
|
||||||
import mage.view.ChatMessage.MessageColor;
|
import mage.view.ChatMessage.MessageColor;
|
||||||
import mage.view.ChatMessage.MessageType;
|
import mage.view.ChatMessage.MessageType;
|
||||||
|
@ -220,6 +223,27 @@ public enum ChatManager {
|
||||||
chatSessions.get(chatId).broadcastInfoToUser(user, message);
|
chatSessions.get(chatId).broadcastInfoToUser(user, message);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (command.startsWith("GAME")) {
|
||||||
|
message += "<br/>" + GameManager.instance.getChatId(chatId);
|
||||||
|
ChatSession session = chatSessions.get(chatId);
|
||||||
|
if (session != null && session.getInfo() != null) {
|
||||||
|
String gameId = session.getInfo();
|
||||||
|
if (gameId.startsWith("Game ")) {
|
||||||
|
UUID id = java.util.UUID.fromString(gameId.substring(5, gameId.length()));
|
||||||
|
for (Entry<UUID, GameController> entry : GameManager.instance.getGameController().entrySet()) {
|
||||||
|
if (entry.getKey().equals(id)) {
|
||||||
|
GameController controller = entry.getValue();
|
||||||
|
if (controller != null) {
|
||||||
|
message += controller.getGameStateDebugMessage();
|
||||||
|
chatSessions.get(chatId).broadcastInfoToUser(user, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (command.startsWith("CARD ")) {
|
if (command.startsWith("CARD ")) {
|
||||||
Matcher matchPattern = getCardTextPattern.matcher(message.toLowerCase());
|
Matcher matchPattern = getCardTextPattern.matcher(message.toLowerCase());
|
||||||
if (matchPattern.find()) {
|
if (matchPattern.find()) {
|
||||||
|
@ -289,18 +313,18 @@ public enum ChatManager {
|
||||||
public void sendReconnectMessage(UUID userId) {
|
public void sendReconnectMessage(UUID userId) {
|
||||||
UserManager.instance.getUser(userId).ifPresent(user
|
UserManager.instance.getUser(userId).ifPresent(user
|
||||||
-> getChatSessions()
|
-> getChatSessions()
|
||||||
.stream()
|
.stream()
|
||||||
.filter(chat -> chat.hasUser(userId))
|
.filter(chat -> chat.hasUser(userId))
|
||||||
.forEach(chatSession -> chatSession.broadcast(null, user.getName() + " has reconnected", MessageColor.BLUE, true, MessageType.STATUS, null)));
|
.forEach(chatSession -> chatSession.broadcast(null, user.getName() + " has reconnected", MessageColor.BLUE, true, MessageType.STATUS, null)));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendLostConnectionMessage(UUID userId, DisconnectReason reason) {
|
public void sendLostConnectionMessage(UUID userId, DisconnectReason reason) {
|
||||||
UserManager.instance.getUser(userId).ifPresent(user
|
UserManager.instance.getUser(userId).ifPresent(user
|
||||||
-> getChatSessions()
|
-> getChatSessions()
|
||||||
.stream()
|
.stream()
|
||||||
.filter(chat -> chat.hasUser(userId))
|
.filter(chat -> chat.hasUser(userId))
|
||||||
.forEach(chatSession -> chatSession.broadcast(null, user.getName() + reason.getMessage(), MessageColor.BLUE, true, MessageType.STATUS, null)));
|
.forEach(chatSession -> chatSession.broadcast(null, user.getName() + reason.getMessage(), MessageColor.BLUE, true, MessageType.STATUS, null)));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -990,7 +990,7 @@ public class TableController {
|
||||||
|| !match.isDoneSideboarding()
|
|| !match.isDoneSideboarding()
|
||||||
|| (!matchPlayer.hasQuit() && match.getGame() != null && matchPlayer.getPlayer().isInGame())) {
|
|| (!matchPlayer.hasQuit() && match.getGame() != null && matchPlayer.getPlayer().isInGame())) {
|
||||||
Optional<User> user = UserManager.instance.getUser(userPlayerEntry.getKey());
|
Optional<User> user = UserManager.instance.getUser(userPlayerEntry.getKey());
|
||||||
if (!user.isPresent()) {
|
if (!user.isPresent() || user.get().isActive()) {
|
||||||
logger.warn("- Active user of match is missing: " + matchPlayer.getName());
|
logger.warn("- Active user of match is missing: " + matchPlayer.getName());
|
||||||
logger.warn("-- matchId:" + match.getId());
|
logger.warn("-- matchId:" + match.getId());
|
||||||
logger.warn("-- userId:" + userPlayerEntry.getKey());
|
logger.warn("-- userId:" + userPlayerEntry.getKey());
|
||||||
|
|
|
@ -50,6 +50,7 @@ import mage.constants.Zone;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.GameException;
|
import mage.game.GameException;
|
||||||
import mage.game.GameOptions;
|
import mage.game.GameOptions;
|
||||||
|
import mage.game.GameState;
|
||||||
import mage.game.Table;
|
import mage.game.Table;
|
||||||
import mage.game.events.Listener;
|
import mage.game.events.Listener;
|
||||||
import mage.game.events.PlayerQueryEvent;
|
import mage.game.events.PlayerQueryEvent;
|
||||||
|
@ -1088,4 +1089,97 @@ public class GameController implements GameCallback {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getGameStateDebugMessage() {
|
||||||
|
if (game == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
GameState state = game.getState();
|
||||||
|
if (state == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("<br/>Game State:<br/><font size=-2>");
|
||||||
|
sb.append(state);
|
||||||
|
|
||||||
|
sb.append("<br>Active player is: ");
|
||||||
|
sb.append(game.getPlayer(state.getActivePlayerId()).getName());
|
||||||
|
sb.append("<br>isGameOver: ");
|
||||||
|
sb.append(state.isGameOver());
|
||||||
|
sb.append("<br>Current phase is: ");
|
||||||
|
sb.append(state.getTurn().getPhase());
|
||||||
|
sb.append("<br>getBattlefield: ");
|
||||||
|
sb.append(state.getBattlefield());
|
||||||
|
sb.append("<br>getChoosingPlayerId: ");
|
||||||
|
if (state.getChoosingPlayerId() != null) {
|
||||||
|
sb.append(game.getPlayer(state.getChoosingPlayerId()).getName());
|
||||||
|
} else {
|
||||||
|
sb.append("noone!");
|
||||||
|
}
|
||||||
|
sb.append("<br>getCombat: ");
|
||||||
|
sb.append(state.getCombat());
|
||||||
|
sb.append("<br>getCommand: ");
|
||||||
|
sb.append(state.getCommand());
|
||||||
|
sb.append("<br>getContinuousEffects: ");
|
||||||
|
sb.append(state.getContinuousEffects());
|
||||||
|
sb.append("<br>getCopiedCards: ");
|
||||||
|
sb.append(state.getCopiedCards());
|
||||||
|
sb.append("<br>getDelayed: ");
|
||||||
|
sb.append(state.getDelayed());
|
||||||
|
sb.append("<br>getDesignations: ");
|
||||||
|
sb.append(state.getDesignations());
|
||||||
|
sb.append("<br>getExile: ");
|
||||||
|
sb.append(state.getExile());
|
||||||
|
sb.append("<br>getMonarchId: ");
|
||||||
|
sb.append(state.getMonarchId());
|
||||||
|
sb.append("<br>getNextPermanentOrderNumber: ");
|
||||||
|
sb.append(state.getNextPermanentOrderNumber());
|
||||||
|
sb.append("<br>getPlayerByOrderId: ");
|
||||||
|
if (state.getPlayerByOrderId() != null) {
|
||||||
|
sb.append(game.getPlayer(state.getPlayerByOrderId()).getName());
|
||||||
|
} else {
|
||||||
|
sb.append("noone!");
|
||||||
|
}
|
||||||
|
sb.append("<br>getPlayerList: ");
|
||||||
|
sb.append(state.getPlayerList());
|
||||||
|
sb.append("<br>getPlayers: ");
|
||||||
|
sb.append(state.getPlayers());
|
||||||
|
sb.append("<br>Player with Priority is: ");
|
||||||
|
if (state.getPriorityPlayerId() != null) {
|
||||||
|
sb.append(game.getPlayer(state.getPriorityPlayerId()).getName());
|
||||||
|
} else {
|
||||||
|
sb.append("noone!");
|
||||||
|
}
|
||||||
|
sb.append("<br>getRevealed: ");
|
||||||
|
sb.append(state.getRevealed());
|
||||||
|
sb.append("<br>getSpecialActions: ");
|
||||||
|
sb.append(state.getSpecialActions());
|
||||||
|
sb.append("<br>getStack: ");
|
||||||
|
sb.append(state.getStack());
|
||||||
|
sb.append("<br>getStepNum: ");
|
||||||
|
sb.append(state.getStepNum());
|
||||||
|
sb.append("<br>getTriggers: ");
|
||||||
|
sb.append(state.getTriggers());
|
||||||
|
sb.append("<br>getTurn: ");
|
||||||
|
sb.append(state.getTurn());
|
||||||
|
sb.append("<br>getTurnId: ");
|
||||||
|
sb.append(state.getTurnId());
|
||||||
|
sb.append("<br>getTurnMods: ");
|
||||||
|
sb.append(state.getTurnMods());
|
||||||
|
sb.append("<br>getTurnNum: ");
|
||||||
|
sb.append(state.getTurnNum());
|
||||||
|
sb.append("<br>Future Timeout:");
|
||||||
|
if (futureTimeout != null) {
|
||||||
|
sb.append("Cancelled?=");
|
||||||
|
sb.append(futureTimeout.isCancelled());
|
||||||
|
sb.append(",,,Done?=");
|
||||||
|
sb.append(futureTimeout.isDone());
|
||||||
|
sb.append(",,,GetDelay?=");
|
||||||
|
sb.append((int) futureTimeout.getDelay(TimeUnit.SECONDS));
|
||||||
|
} else {
|
||||||
|
sb.append("Not using future Timeout!");
|
||||||
|
}
|
||||||
|
sb.append("</font>");
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
*/
|
*/
|
||||||
package mage.cards.a;
|
package mage.cards.a;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.Mode;
|
import mage.abilities.Mode;
|
||||||
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
|
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
|
||||||
|
@ -44,8 +45,6 @@ import mage.game.permanent.Permanent;
|
||||||
import mage.target.TargetPermanent;
|
import mage.target.TargetPermanent;
|
||||||
import mage.target.targetpointer.FixedTarget;
|
import mage.target.targetpointer.FixedTarget;
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author LevelX2
|
* @author LevelX2
|
||||||
|
@ -53,8 +52,7 @@ import java.util.UUID;
|
||||||
public class ActOfAuthority extends CardImpl {
|
public class ActOfAuthority extends CardImpl {
|
||||||
|
|
||||||
public ActOfAuthority(UUID ownerId, CardSetInfo setInfo) {
|
public ActOfAuthority(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{W}{W}");
|
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}{W}");
|
||||||
|
|
||||||
|
|
||||||
// When Act of Authority enters the battlefield, you may exile target artifact or enchantment.
|
// When Act of Authority enters the battlefield, you may exile target artifact or enchantment.
|
||||||
Ability ability = new EntersBattlefieldTriggeredAbility(new ExileTargetEffect(), true);
|
Ability ability = new EntersBattlefieldTriggeredAbility(new ExileTargetEffect(), true);
|
||||||
|
|
|
@ -103,7 +103,7 @@ class BackFromTheBrinkCost extends CostImpl {
|
||||||
if (controller != null) {
|
if (controller != null) {
|
||||||
Card card = controller.getGraveyard().get(targets.getFirstTarget(), game);
|
Card card = controller.getGraveyard().get(targets.getFirstTarget(), game);
|
||||||
if (card != null && controller.moveCards(card, Zone.EXILED, ability, game)) {
|
if (card != null && controller.moveCards(card, Zone.EXILED, ability, game)) {
|
||||||
ability.getEffects().get(0).setTargetPointer(new FixedTarget(card.getId()));
|
ability.getEffects().get(0).setTargetPointer(new FixedTarget(card.getId(), game.getState().getZoneChangeCounter(card.getId())));
|
||||||
paid = card.getManaCost().pay(ability, game, sourceId, controllerId, noMana);
|
paid = card.getManaCost().pay(ability, game, sourceId, controllerId, noMana);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,12 +85,12 @@ class BarrinsUnmakingEffect extends OneShotEffect {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Permanent permanent = game.getPermanent(source.getFirstTarget());
|
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
|
||||||
if (permanent != null) {
|
if (permanent != null) {
|
||||||
Condition condition = new MostCommonColorCondition(permanent.getColor(game));
|
Condition condition = new MostCommonColorCondition(permanent.getColor(game));
|
||||||
if (condition.apply(game, source)) {
|
if (condition.apply(game, source)) {
|
||||||
Effect effect = new ReturnToHandTargetEffect();
|
Effect effect = new ReturnToHandTargetEffect();
|
||||||
effect.setTargetPointer(new FixedTarget(permanent.getId()));
|
effect.setTargetPointer(new FixedTarget(permanent, game));
|
||||||
return effect.apply(game, source);
|
return effect.apply(game, source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,6 @@ package mage.cards.c;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.costs.Cost;
|
import mage.abilities.costs.Cost;
|
||||||
import mage.abilities.costs.common.DiscardTargetCost;
|
|
||||||
import mage.abilities.costs.common.DiscardXTargetCost;
|
import mage.abilities.costs.common.DiscardXTargetCost;
|
||||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||||
import mage.abilities.dynamicvalue.DynamicValue;
|
import mage.abilities.dynamicvalue.DynamicValue;
|
||||||
|
@ -82,8 +81,8 @@ class ConflagrateVariableValue implements DynamicValue {
|
||||||
public int calculate(Game game, Ability sourceAbility, Effect effect) {
|
public int calculate(Game game, Ability sourceAbility, Effect effect) {
|
||||||
int xValue = sourceAbility.getManaCostsToPay().getX();
|
int xValue = sourceAbility.getManaCostsToPay().getX();
|
||||||
for (Cost cost : sourceAbility.getCosts()) {
|
for (Cost cost : sourceAbility.getCosts()) {
|
||||||
if (cost instanceof DiscardTargetCost) {
|
if (cost instanceof DiscardXTargetCost) {
|
||||||
xValue = ((DiscardTargetCost) cost).getCards().size();
|
xValue = ((DiscardXTargetCost) cost).getAmount();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return xValue;
|
return xValue;
|
||||||
|
|
|
@ -68,8 +68,7 @@ public class DiamondKaleidoscope extends CardImpl {
|
||||||
this.addAbility(ability);
|
this.addAbility(ability);
|
||||||
|
|
||||||
// Sacrifice a Prism token: Add one mana of any color to your mana pool.
|
// Sacrifice a Prism token: Add one mana of any color to your mana pool.
|
||||||
ability = new AnyColorManaAbility();
|
ability = new AnyColorManaAbility(new SacrificeTargetCost(new TargetControlledPermanent(filter)));
|
||||||
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter)));
|
|
||||||
this.addAbility(ability);
|
this.addAbility(ability);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
*/
|
*/
|
||||||
package mage.cards.d;
|
package mage.cards.d;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import mage.MageInt;
|
import mage.MageInt;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
|
@ -52,7 +53,7 @@ public class DreamThief extends CardImpl {
|
||||||
private static final String rule = "draw a card if you've cast another blue spell this turn";
|
private static final String rule = "draw a card if you've cast another blue spell this turn";
|
||||||
|
|
||||||
public DreamThief(UUID ownerId, CardSetInfo setInfo) {
|
public DreamThief(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{U}");
|
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}");
|
||||||
this.subtype.add(SubType.FAERIE);
|
this.subtype.add(SubType.FAERIE);
|
||||||
this.subtype.add(SubType.ROGUE);
|
this.subtype.add(SubType.ROGUE);
|
||||||
|
|
||||||
|
@ -84,9 +85,12 @@ class CastBlueSpellThisTurnCondition implements Condition {
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
SpellsCastWatcher watcher = (SpellsCastWatcher) game.getState().getWatchers().get(SpellsCastWatcher.class.getSimpleName());
|
SpellsCastWatcher watcher = (SpellsCastWatcher) game.getState().getWatchers().get(SpellsCastWatcher.class.getSimpleName());
|
||||||
if (watcher != null) {
|
if (watcher != null) {
|
||||||
for (Spell spell : watcher.getSpellsCastThisTurn(source.getControllerId())) {
|
List<Spell> spells = watcher.getSpellsCastThisTurn(source.getControllerId());
|
||||||
if (!spell.getSourceId().equals(source.getSourceId()) && spell.getColor(game).isBlue()) {
|
if (spells != null) {
|
||||||
return true;
|
for (Spell spell : spells) {
|
||||||
|
if (!spell.getSourceId().equals(source.getSourceId()) && spell.getColor(game).isBlue()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,10 +27,13 @@
|
||||||
*/
|
*/
|
||||||
package mage.cards.g;
|
package mage.cards.g;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
import mage.MageObjectReference;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility;
|
import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility;
|
||||||
import mage.abilities.effects.OneShotEffect;
|
import mage.abilities.effects.OneShotEffect;
|
||||||
import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect;
|
|
||||||
import mage.abilities.effects.common.RegenerateTargetEffect;
|
import mage.abilities.effects.common.RegenerateTargetEffect;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
|
@ -43,10 +46,6 @@ import mage.players.Player;
|
||||||
import mage.target.common.TargetCreaturePermanent;
|
import mage.target.common.TargetCreaturePermanent;
|
||||||
import mage.watchers.common.BlockedAttackerWatcher;
|
import mage.watchers.common.BlockedAttackerWatcher;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author LevelX2
|
* @author LevelX2
|
||||||
|
@ -60,8 +59,7 @@ public class GazeOfTheGorgon extends CardImpl {
|
||||||
// Regenerate target creature. At end of combat, destroy all creatures that blocked or were blocked by that creature this turn.
|
// Regenerate target creature. At end of combat, destroy all creatures that blocked or were blocked by that creature this turn.
|
||||||
this.getSpellAbility().addEffect(new RegenerateTargetEffect());
|
this.getSpellAbility().addEffect(new RegenerateTargetEffect());
|
||||||
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
|
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
|
||||||
this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect(
|
this.getSpellAbility().addEffect(new GazeOfTheGorgonCreateDelayedTriggeredAbilityEffect());
|
||||||
new AtTheEndOfCombatDelayedTriggeredAbility(new GazeOfTheGorgonEffect())));
|
|
||||||
this.getSpellAbility().addWatcher(new BlockedAttackerWatcher());
|
this.getSpellAbility().addWatcher(new BlockedAttackerWatcher());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,15 +73,46 @@ public class GazeOfTheGorgon extends CardImpl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class GazeOfTheGorgonCreateDelayedTriggeredAbilityEffect extends OneShotEffect {
|
||||||
|
|
||||||
|
public GazeOfTheGorgonCreateDelayedTriggeredAbilityEffect() {
|
||||||
|
super(Outcome.Benefit);
|
||||||
|
this.staticText = "At this turn's next end of combat, destroy all creatures that blocked or were blocked by it this turn";
|
||||||
|
}
|
||||||
|
|
||||||
|
public GazeOfTheGorgonCreateDelayedTriggeredAbilityEffect(final GazeOfTheGorgonCreateDelayedTriggeredAbilityEffect effect) {
|
||||||
|
super(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GazeOfTheGorgonCreateDelayedTriggeredAbilityEffect copy() {
|
||||||
|
return new GazeOfTheGorgonCreateDelayedTriggeredAbilityEffect(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
if (!source.getTargets().isEmpty() && source.getFirstTarget() != null) {
|
||||||
|
MageObjectReference mor = new MageObjectReference(source.getFirstTarget(), game);
|
||||||
|
AtTheEndOfCombatDelayedTriggeredAbility delayedAbility = new AtTheEndOfCombatDelayedTriggeredAbility(new GazeOfTheGorgonEffect(mor));
|
||||||
|
game.addDelayedTriggeredAbility(delayedAbility, source);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class GazeOfTheGorgonEffect extends OneShotEffect {
|
class GazeOfTheGorgonEffect extends OneShotEffect {
|
||||||
|
|
||||||
public GazeOfTheGorgonEffect() {
|
MageObjectReference targetCreature;
|
||||||
|
|
||||||
|
public GazeOfTheGorgonEffect(MageObjectReference targetCreature) {
|
||||||
super(Outcome.DestroyPermanent);
|
super(Outcome.DestroyPermanent);
|
||||||
this.staticText = "destroy all creatures that blocked or were blocked by that creature this turn";
|
this.targetCreature = targetCreature;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GazeOfTheGorgonEffect(final GazeOfTheGorgonEffect effect) {
|
public GazeOfTheGorgonEffect(final GazeOfTheGorgonEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
|
targetCreature = effect.targetCreature;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -94,14 +123,13 @@ class GazeOfTheGorgonEffect extends OneShotEffect {
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Player controller = game.getPlayer(source.getControllerId());
|
Player controller = game.getPlayer(source.getControllerId());
|
||||||
Permanent targetCreature = game.getPermanentOrLKIBattlefield(source.getTargets().getFirstTarget());
|
|
||||||
if (controller != null && targetCreature != null) {
|
if (controller != null && targetCreature != null) {
|
||||||
BlockedAttackerWatcher watcher = (BlockedAttackerWatcher) game.getState().getWatchers().get(BlockedAttackerWatcher.class.getSimpleName());
|
BlockedAttackerWatcher watcher = (BlockedAttackerWatcher) game.getState().getWatchers().get(BlockedAttackerWatcher.class.getSimpleName());
|
||||||
if (watcher != null) {
|
if (watcher != null) {
|
||||||
List<Permanent> toDestroy = new ArrayList<>();
|
List<Permanent> toDestroy = new ArrayList<>();
|
||||||
for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game)) {
|
for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game)) {
|
||||||
if (!creature.getId().equals(targetCreature.getId())) {
|
if (!creature.getId().equals(targetCreature.getSourceId())) {
|
||||||
if (watcher.creatureHasBlockedAttacker(creature, targetCreature, game) || watcher.creatureHasBlockedAttacker(targetCreature, creature, game)) {
|
if (watcher.creatureHasBlockedAttacker(new MageObjectReference(creature, game), targetCreature, game) || watcher.creatureHasBlockedAttacker(targetCreature, new MageObjectReference(creature, game), game)) {
|
||||||
toDestroy.add(creature);
|
toDestroy.add(creature);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,35 +27,34 @@
|
||||||
*/
|
*/
|
||||||
package mage.cards.h;
|
package mage.cards.h;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import mage.MageInt;
|
import mage.MageInt;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility;
|
import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility;
|
||||||
import mage.abilities.effects.AsThoughEffectImpl;
|
|
||||||
import mage.abilities.effects.ContinuousEffect;
|
|
||||||
import mage.abilities.effects.OneShotEffect;
|
import mage.abilities.effects.OneShotEffect;
|
||||||
import mage.abilities.keyword.FlyingAbility;
|
import mage.abilities.keyword.FlyingAbility;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
|
import mage.cards.Cards;
|
||||||
|
import mage.cards.CardsImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
import mage.constants.AsThoughEffectType;
|
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
import mage.constants.SubType;
|
import mage.constants.SubType;
|
||||||
import mage.constants.Duration;
|
|
||||||
import mage.constants.Outcome;
|
import mage.constants.Outcome;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
|
import mage.filter.FilterCard;
|
||||||
import mage.filter.common.FilterControlledPermanent;
|
import mage.filter.common.FilterControlledPermanent;
|
||||||
import mage.filter.common.FilterNonlandCard;
|
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
import mage.target.common.TargetCardInExile;
|
import mage.target.TargetCard;
|
||||||
import mage.target.targetpointer.FixedTarget;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author jeffwadsworth
|
* @author jeffwadsworth & L_J
|
||||||
*/
|
*/
|
||||||
public class HellcarverDemon extends CardImpl {
|
public class HellcarverDemon extends CardImpl {
|
||||||
|
|
||||||
|
@ -84,9 +83,6 @@ public class HellcarverDemon extends CardImpl {
|
||||||
|
|
||||||
class HellcarverDemonEffect extends OneShotEffect {
|
class HellcarverDemonEffect extends OneShotEffect {
|
||||||
|
|
||||||
private static final FilterControlledPermanent filterPermanents = new FilterControlledPermanent("Permanent");
|
|
||||||
private static FilterNonlandCard filter = new FilterNonlandCard("nonland card exiled with Hellcarver Demon");
|
|
||||||
|
|
||||||
public HellcarverDemonEffect() {
|
public HellcarverDemonEffect() {
|
||||||
super(Outcome.PlayForFree);
|
super(Outcome.PlayForFree);
|
||||||
staticText = "sacrifice all other permanents you control and discard your hand. Exile the top six cards of your library. You may cast any number of nonland cards exiled this way without paying their mana costs.";
|
staticText = "sacrifice all other permanents you control and discard your hand. Exile the top six cards of your library. You may cast any number of nonland cards exiled this way without paying their mana costs.";
|
||||||
|
@ -99,41 +95,43 @@ class HellcarverDemonEffect extends OneShotEffect {
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Player controller = game.getPlayer(source.getControllerId());
|
Player controller = game.getPlayer(source.getControllerId());
|
||||||
Permanent hellcarverDemon = game.getPermanent(source.getSourceId());
|
Permanent sourceObject = game.getPermanentOrLKIBattlefield(source.getSourceId());
|
||||||
|
if (controller != null && sourceObject != null) {
|
||||||
for (Permanent permanent : game.getBattlefield().getActivePermanents(filterPermanents, source.getControllerId(), game)) {
|
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(source.getControllerId())) {
|
||||||
if (!Objects.equals(permanent, hellcarverDemon)) {
|
if (!Objects.equals(permanent, sourceObject)) {
|
||||||
permanent.sacrifice(source.getSourceId(), game);
|
permanent.sacrifice(source.getSourceId(), game);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!controller.getHand().isEmpty()) {
|
||||||
if (controller != null && !controller.getHand().isEmpty()) {
|
int cardsInHand = controller.getHand().size();
|
||||||
int cardsInHand = controller.getHand().size();
|
controller.discard(cardsInHand, false, source, game);
|
||||||
controller.discard(cardsInHand, false, source, game);
|
}
|
||||||
}
|
// move cards from library to exile
|
||||||
|
Set<Card> currentExiledCards = new HashSet<>();
|
||||||
for (int i = 0; i < 6; i++) {
|
currentExiledCards.addAll(controller.getLibrary().getTopCards(game, 6));
|
||||||
if (controller != null
|
controller.moveCardsToExile(currentExiledCards, source, game, true, source.getSourceId(), sourceObject.getIdName());
|
||||||
&& controller.getLibrary().hasCards()) {
|
|
||||||
Card topCard = controller.getLibrary().getFromTop(game);
|
// cast the possible cards without paying the mana
|
||||||
topCard.moveToExile(source.getSourceId(), "Cards exiled by Hellcarver Demon", source.getSourceId(), game);
|
Cards cardsToCast = new CardsImpl();
|
||||||
}
|
cardsToCast.addAll(currentExiledCards);
|
||||||
}
|
boolean alreadyCast = false;
|
||||||
|
while (!cardsToCast.isEmpty()
|
||||||
while (controller != null
|
&& controller.canRespond()) {
|
||||||
&& controller.canRespond()
|
if (!controller.chooseUse(outcome, "Cast a" + (alreadyCast ? "nother" : "" ) + " card exiled with " + sourceObject.getLogName() + " without paying its mana cost?", source, game)) {
|
||||||
&& controller.chooseUse(Outcome.PlayForFree, controller.getLogName() + " can cast another nonland card exiled with Hellcarver Demon without paying that card's mana cost.", source, game)) {
|
break;
|
||||||
TargetCardInExile target = new TargetCardInExile(filter, source.getSourceId());
|
}
|
||||||
while (controller.chooseUse(Outcome.PlayForFree, "Cast another spell exiled by Hellcarver Demon?", source, game)) {
|
TargetCard targetCard = new TargetCard(1, Zone.EXILED, new FilterCard("nonland card to cast for free"));
|
||||||
controller.choose(Outcome.PlayForFree, game.getExile().getExileZone(source.getSourceId()), target, game);
|
if (controller.choose(Outcome.PlayForFree, cardsToCast, targetCard, game)) {
|
||||||
Card card = game.getCard(target.getFirstTarget());
|
alreadyCast = true;
|
||||||
if (card != null) {
|
Card card = game.getCard(targetCard.getFirstTarget());
|
||||||
ContinuousEffect effect = new HellcarverDemonCastFromExileEffect();
|
if (card != null) {
|
||||||
effect.setTargetPointer(new FixedTarget(card.getId()));
|
if (controller.cast(card.getSpellAbility(), game, true)) {
|
||||||
game.addEffect(effect, source);
|
cardsToCast.remove(card);
|
||||||
controller.cast(card.getSpellAbility(), game, true);
|
} else {
|
||||||
|
game.informPlayer(controller, "You're not able to cast " + card.getIdName() + " or you canceled the casting.");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
target.clearChosen();
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -145,33 +143,3 @@ class HellcarverDemonEffect extends OneShotEffect {
|
||||||
return new HellcarverDemonEffect(this);
|
return new HellcarverDemonEffect(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class HellcarverDemonCastFromExileEffect extends AsThoughEffectImpl {
|
|
||||||
|
|
||||||
public HellcarverDemonCastFromExileEffect() {
|
|
||||||
super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.Custom, Outcome.Benefit);
|
|
||||||
staticText = "You may play the card from exile without paying its mana cost";
|
|
||||||
}
|
|
||||||
|
|
||||||
public HellcarverDemonCastFromExileEffect(final HellcarverDemonCastFromExileEffect effect) {
|
|
||||||
super(effect);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean apply(Game game, Ability source) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public HellcarverDemonCastFromExileEffect copy() {
|
|
||||||
return new HellcarverDemonCastFromExileEffect(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) {
|
|
||||||
if (targetPointer.getTargets(game, source).contains(sourceId)) {
|
|
||||||
return game.getState().getZone(sourceId) == Zone.EXILED;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -12,25 +12,24 @@ import mage.filter.common.FilterControlledPermanent;
|
||||||
|
|
||||||
public class KaerveksSpite extends CardImpl {
|
public class KaerveksSpite extends CardImpl {
|
||||||
|
|
||||||
private FilterControlledPermanent permanentsYouControl = new FilterControlledPermanent("all permanents you control");
|
|
||||||
|
|
||||||
public KaerveksSpite(UUID ownerId, CardSetInfo cardSetInfo) {
|
public KaerveksSpite(UUID ownerId, CardSetInfo cardSetInfo) {
|
||||||
super(ownerId, cardSetInfo, new CardType[]{CardType.INSTANT}, "{B}{B}{B}");
|
super(ownerId, cardSetInfo, new CardType[]{CardType.INSTANT}, "{B}{B}{B}");
|
||||||
|
|
||||||
//As an additional cost to cast Kaervek's Spite, sacrifice all permanents you control and discard your hand.
|
// As an additional cost to cast Kaervek's Spite, sacrifice all permanents you control and discard your hand.
|
||||||
this.getSpellAbility().addCost(new SacrificeAllCost(permanentsYouControl));
|
this.getSpellAbility().addCost(new SacrificeAllCost(new FilterControlledPermanent("all permanents you control")));
|
||||||
this.getSpellAbility().addCost(new DiscardHandCost());
|
this.getSpellAbility().addCost(new DiscardHandCost());
|
||||||
|
|
||||||
//Target player loses 5 life.
|
// Target player loses 5 life.
|
||||||
Effect effect = new LoseLifeTargetEffect(5);
|
Effect effect = new LoseLifeTargetEffect(5);
|
||||||
this.getSpellAbility().addEffect(effect);
|
this.getSpellAbility().addEffect(effect);
|
||||||
}
|
}
|
||||||
|
|
||||||
public KaerveksSpite(final KaerveksSpite other){
|
public KaerveksSpite(final KaerveksSpite other) {
|
||||||
super(other);
|
super(other);
|
||||||
}
|
}
|
||||||
|
|
||||||
public KaerveksSpite copy(){
|
@Override
|
||||||
|
public KaerveksSpite copy() {
|
||||||
return new KaerveksSpite(this);
|
return new KaerveksSpite(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,8 +38,8 @@ import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbil
|
||||||
import mage.abilities.costs.common.TapSourceCost;
|
import mage.abilities.costs.common.TapSourceCost;
|
||||||
import mage.abilities.costs.mana.GenericManaCost;
|
import mage.abilities.costs.mana.GenericManaCost;
|
||||||
import mage.abilities.effects.OneShotEffect;
|
import mage.abilities.effects.OneShotEffect;
|
||||||
import mage.abilities.effects.common.ExileTargetEffect;
|
|
||||||
import mage.abilities.effects.common.CreateTokenCopyTargetEffect;
|
import mage.abilities.effects.common.CreateTokenCopyTargetEffect;
|
||||||
|
import mage.abilities.effects.common.ExileTargetEffect;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
|
@ -122,7 +122,7 @@ class MimicVatTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
&& !(permanent instanceof PermanentToken)
|
&& !(permanent instanceof PermanentToken)
|
||||||
&& permanent.isCreature()) {
|
&& permanent.isCreature()) {
|
||||||
|
|
||||||
getEffects().get(0).setTargetPointer(new FixedTarget(permanent.getId()));
|
getEffects().get(0).setTargetPointer(new FixedTarget(permanent.getId(), game));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -152,22 +152,22 @@ class MimicVatEffect extends OneShotEffect {
|
||||||
if (controller == null || permanent == null) {
|
if (controller == null || permanent == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// return older cards to graveyard
|
|
||||||
Set<Card> toGraveyard = new HashSet<>();
|
|
||||||
for (UUID imprintedId : permanent.getImprinted()) {
|
|
||||||
Card card = game.getCard(imprintedId);
|
|
||||||
if (card != null) {
|
|
||||||
toGraveyard.add(card);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
controller.moveCards(toGraveyard, Zone.GRAVEYARD, source, game);
|
|
||||||
permanent.clearImprinted(game);
|
|
||||||
|
|
||||||
// Imprint a new one
|
// Imprint a new one
|
||||||
Card card = game.getCard(getTargetPointer().getFirst(game, source));
|
Card newCard = game.getCard(getTargetPointer().getFirst(game, source));
|
||||||
if (card != null) {
|
if (newCard != null) {
|
||||||
controller.moveCardsToExile(card, source, game, true, source.getSourceId(), permanent.getName() + " (Imprint)");
|
// return older cards to graveyard
|
||||||
permanent.imprint(card.getId(), game);
|
Set<Card> toGraveyard = new HashSet<>();
|
||||||
|
for (UUID imprintedId : permanent.getImprinted()) {
|
||||||
|
Card card = game.getCard(imprintedId);
|
||||||
|
if (card != null) {
|
||||||
|
toGraveyard.add(card);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
controller.moveCards(toGraveyard, Zone.GRAVEYARD, source, game);
|
||||||
|
permanent.clearImprinted(game);
|
||||||
|
|
||||||
|
controller.moveCardsToExile(newCard, source, game, true, source.getSourceId(), permanent.getName() + " (Imprint)");
|
||||||
|
permanent.imprint(newCard.getId(), game);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -50,7 +50,7 @@ import mage.game.events.NumberOfTriggersEvent;
|
||||||
public class Panharmonicon extends CardImpl {
|
public class Panharmonicon extends CardImpl {
|
||||||
|
|
||||||
public Panharmonicon(UUID ownerId, CardSetInfo setInfo) {
|
public Panharmonicon(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{4}");
|
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}");
|
||||||
|
|
||||||
// If an artifact or creature entering the battlefield causes a triggered ability of a permanent you control to trigger, that ability triggers an additional time.
|
// If an artifact or creature entering the battlefield causes a triggered ability of a permanent you control to trigger, that ability triggers an additional time.
|
||||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PanharmoniconEffect()));
|
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PanharmoniconEffect()));
|
||||||
|
@ -95,7 +95,9 @@ class PanharmoniconEffect extends ReplacementEffectImpl {
|
||||||
if (source.getControllerId().equals(event.getPlayerId())) {
|
if (source.getControllerId().equals(event.getPlayerId())) {
|
||||||
GameEvent sourceEvent = numberOfTriggersEvent.getSourceEvent();
|
GameEvent sourceEvent = numberOfTriggersEvent.getSourceEvent();
|
||||||
// Only EtB triggers
|
// Only EtB triggers
|
||||||
if (sourceEvent.getType() == EventType.ENTERS_THE_BATTLEFIELD && sourceEvent instanceof EntersTheBattlefieldEvent) {
|
if (sourceEvent != null
|
||||||
|
&& sourceEvent.getType() == EventType.ENTERS_THE_BATTLEFIELD
|
||||||
|
&& sourceEvent instanceof EntersTheBattlefieldEvent) {
|
||||||
EntersTheBattlefieldEvent entersTheBattlefieldEvent = (EntersTheBattlefieldEvent) sourceEvent;
|
EntersTheBattlefieldEvent entersTheBattlefieldEvent = (EntersTheBattlefieldEvent) sourceEvent;
|
||||||
// Only for entering artifacts or creatures
|
// Only for entering artifacts or creatures
|
||||||
if (entersTheBattlefieldEvent.getTarget().isArtifact()
|
if (entersTheBattlefieldEvent.getTarget().isArtifact()
|
||||||
|
|
133
Mage.Sets/src/mage/cards/p/PowerLeak.java
Normal file
133
Mage.Sets/src/mage/cards/p/PowerLeak.java
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
/*
|
||||||
|
* 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 java.util.UUID;
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
|
||||||
|
import mage.abilities.costs.mana.GenericManaCost;
|
||||||
|
import mage.abilities.costs.mana.ManaCost;
|
||||||
|
import mage.abilities.costs.mana.ManaCosts;
|
||||||
|
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||||
|
import mage.abilities.effects.OneShotEffect;
|
||||||
|
import mage.abilities.effects.common.AttachEffect;
|
||||||
|
import mage.abilities.effects.common.PreventDamageByTargetEffect;
|
||||||
|
import mage.abilities.keyword.EnchantAbility;
|
||||||
|
import mage.cards.CardImpl;
|
||||||
|
import mage.cards.CardSetInfo;
|
||||||
|
import mage.constants.CardType;
|
||||||
|
import mage.constants.SubType;
|
||||||
|
import mage.constants.Duration;
|
||||||
|
import mage.constants.Outcome;
|
||||||
|
import mage.constants.TargetController;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.game.permanent.Permanent;
|
||||||
|
import mage.players.Player;
|
||||||
|
import mage.target.TargetPermanent;
|
||||||
|
import mage.target.common.TargetEnchantmentPermanent;
|
||||||
|
import mage.target.targetpointer.FixedTarget;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author L_J
|
||||||
|
*/
|
||||||
|
public class PowerLeak extends CardImpl {
|
||||||
|
|
||||||
|
public PowerLeak(UUID ownerId, CardSetInfo setInfo) {
|
||||||
|
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{U}");
|
||||||
|
this.subtype.add(SubType.AURA);
|
||||||
|
|
||||||
|
// Enchant enchantment
|
||||||
|
TargetPermanent auraTarget = new TargetEnchantmentPermanent();
|
||||||
|
this.getSpellAbility().addTarget(auraTarget);
|
||||||
|
this.getSpellAbility().addEffect(new AttachEffect(Outcome.Detriment));
|
||||||
|
this.addAbility(new EnchantAbility(auraTarget.getTargetName()));
|
||||||
|
|
||||||
|
// At the beginning of the upkeep of enchanted enchantment's controller, that player may pay any amount of mana. Power Leak deals 2 damage to that player. Prevent X of that damage, where X is the amount of mana that player paid this way.
|
||||||
|
this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new PowerLeakEffect(), TargetController.CONTROLLER_ATTACHED_TO, false, true, "At the beginning of the upkeep of enchanted enchantment's controller, "));
|
||||||
|
}
|
||||||
|
|
||||||
|
public PowerLeak(final PowerLeak card) {
|
||||||
|
super(card);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PowerLeak copy() {
|
||||||
|
return new PowerLeak(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PowerLeakEffect extends OneShotEffect {
|
||||||
|
|
||||||
|
public PowerLeakEffect() {
|
||||||
|
super(Outcome.Detriment);
|
||||||
|
this.staticText = "that player may pay any amount of mana. {this} deals 2 damage to that player. Prevent X of that damage, where X is the amount of mana that player paid this way";
|
||||||
|
}
|
||||||
|
|
||||||
|
public PowerLeakEffect(final PowerLeakEffect effect) {
|
||||||
|
super(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PowerLeakEffect copy() {
|
||||||
|
return new PowerLeakEffect(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
Player player = game.getPlayer(game.getActivePlayerId());
|
||||||
|
Permanent permanent = game.getPermanentOrLKIBattlefield(source.getSourceId());
|
||||||
|
if (player != null && permanent != null) {
|
||||||
|
ManaCosts<ManaCost> cost = new ManaCostsImpl<>("{X}");
|
||||||
|
String message = "Pay {X} to prevent X damage from " + permanent.getLogName() + "?";
|
||||||
|
int xValue = 0;
|
||||||
|
if (player != null && player.chooseUse(Outcome.Neutral, message, source, game)) {
|
||||||
|
xValue = player.announceXMana(0, Integer.MAX_VALUE, "Choose the amount of mana to pay", game, source);
|
||||||
|
cost.add(new GenericManaCost(xValue));
|
||||||
|
if (cost.pay(source, game, source.getSourceId(), player.getId(), false, null)) {
|
||||||
|
game.informPlayers(player.getLogName() + " paid {" + xValue + "} for " + permanent.getLogName());
|
||||||
|
} else {
|
||||||
|
game.informPlayers(player.getLogName() + " didn't pay {X} for " + permanent.getLogName());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
game.informPlayers(player.getLogName() + " didn't pay {X} for " + permanent.getLogName());
|
||||||
|
}
|
||||||
|
|
||||||
|
PreventDamageByTargetEffect effect = new PreventDamageByTargetEffect(Duration.OneUse, xValue, false);
|
||||||
|
if (xValue != 0 && cost.isPaid()) {
|
||||||
|
effect.setTargetPointer(new FixedTarget(permanent.getId()));
|
||||||
|
game.addEffect(effect, source);
|
||||||
|
}
|
||||||
|
player.damage(2, source.getSourceId(), game, false, true);
|
||||||
|
effect.discard();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
112
Mage.Sets/src/mage/cards/p/PutridCyclops.java
Normal file
112
Mage.Sets/src/mage/cards/p/PutridCyclops.java
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
/*
|
||||||
|
* 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 java.util.UUID;
|
||||||
|
import mage.MageInt;
|
||||||
|
import mage.MageObject;
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||||
|
import mage.abilities.effects.ContinuousEffect;
|
||||||
|
import mage.abilities.effects.OneShotEffect;
|
||||||
|
import mage.abilities.effects.common.continuous.BoostSourceEffect;
|
||||||
|
import mage.abilities.effects.keyword.ScryEffect;
|
||||||
|
import mage.cards.Card;
|
||||||
|
import mage.cards.CardImpl;
|
||||||
|
import mage.cards.CardSetInfo;
|
||||||
|
import mage.cards.CardsImpl;
|
||||||
|
import mage.constants.CardType;
|
||||||
|
import mage.constants.Duration;
|
||||||
|
import mage.constants.Outcome;
|
||||||
|
import mage.constants.SubType;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.players.Player;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author LevelX2
|
||||||
|
*/
|
||||||
|
public class PutridCyclops extends CardImpl {
|
||||||
|
|
||||||
|
public PutridCyclops(UUID ownerId, CardSetInfo setInfo) {
|
||||||
|
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}");
|
||||||
|
|
||||||
|
this.subtype.add(SubType.ZOMBIE);
|
||||||
|
this.subtype.add(SubType.CYCLOPS);
|
||||||
|
this.power = new MageInt(3);
|
||||||
|
this.toughness = new MageInt(3);
|
||||||
|
|
||||||
|
// When Putrid Cyclops enters the battlefield, scry 1, then reveal the top card of your library. Putrid Cyclops gets -X/-X until end of turn, where X is that card's converted mana cost.
|
||||||
|
this.addAbility(new EntersBattlefieldTriggeredAbility(new PutridCyclopEffect()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public PutridCyclops(final PutridCyclops card) {
|
||||||
|
super(card);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PutridCyclops copy() {
|
||||||
|
return new PutridCyclops(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PutridCyclopEffect extends OneShotEffect {
|
||||||
|
|
||||||
|
public PutridCyclopEffect() {
|
||||||
|
super(Outcome.Detriment);
|
||||||
|
this.staticText = "scry 1, then reveal the top card of your library. {this} gets -X/-X until end of turn, where X is that card's converted mana cost"
|
||||||
|
+ " <i>(To scry 1, look at the top card of your library, then you may put that card on the bottom of your library.)</i>";
|
||||||
|
}
|
||||||
|
|
||||||
|
public PutridCyclopEffect(final PutridCyclopEffect effect) {
|
||||||
|
super(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PutridCyclopEffect copy() {
|
||||||
|
return new PutridCyclopEffect(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
Player controller = game.getPlayer(source.getControllerId());
|
||||||
|
MageObject sourceObject = source.getSourceObject(game);
|
||||||
|
if (controller != null && sourceObject != null) {
|
||||||
|
new ScryEffect(1).apply(game, source);
|
||||||
|
Card card = controller.getLibrary().getFromTop(game);
|
||||||
|
if (card != null) {
|
||||||
|
controller.revealCards(sourceObject.getIdName(), new CardsImpl(card), game);
|
||||||
|
int unboost = card.getConvertedManaCost() * -1;
|
||||||
|
ContinuousEffect effect = new BoostSourceEffect(unboost, unboost, Duration.EndOfTurn);
|
||||||
|
game.addEffect(effect, source);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
135
Mage.Sets/src/mage/cards/r/ReversePolarity.java
Normal file
135
Mage.Sets/src/mage/cards/r/ReversePolarity.java
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
/*
|
||||||
|
* 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.r;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.UUID;
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.dynamicvalue.DynamicValue;
|
||||||
|
import mage.abilities.effects.Effect;
|
||||||
|
import mage.abilities.effects.common.GainLifeEffect;
|
||||||
|
import mage.cards.CardImpl;
|
||||||
|
import mage.cards.CardSetInfo;
|
||||||
|
import mage.constants.CardType;
|
||||||
|
import mage.constants.WatcherScope;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.game.events.GameEvent;
|
||||||
|
import mage.game.permanent.Permanent;
|
||||||
|
import mage.watchers.Watcher;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jeffwadsworth, MTGFan & L_J
|
||||||
|
*/
|
||||||
|
public class ReversePolarity extends CardImpl {
|
||||||
|
|
||||||
|
public ReversePolarity(UUID ownerId, CardSetInfo setInfo) {
|
||||||
|
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{W}{W}");
|
||||||
|
|
||||||
|
// You gain X life, where X is twice the damage dealt to you so far this turn by artifacts.
|
||||||
|
this.getSpellAbility().addEffect(new GainLifeEffect(new ReversePolarityAmount(), "You gain X life, where X is twice the damage dealt to you so far this turn by artifacts"));
|
||||||
|
this.getSpellAbility().addWatcher(new ReversePolarityWatcher());
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReversePolarity(final ReversePolarity card) {
|
||||||
|
super(card);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ReversePolarity copy() {
|
||||||
|
return new ReversePolarity(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ReversePolarityAmount implements DynamicValue {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int calculate(Game game, Ability source, Effect effect) {
|
||||||
|
ReversePolarityWatcher watcher = (ReversePolarityWatcher) game.getState().getWatchers().get(ReversePolarityWatcher.class.getSimpleName());
|
||||||
|
if(watcher != null) {
|
||||||
|
return watcher.getArtifactDamageReceivedThisTurn(source.getControllerId()) * 2;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ReversePolarityAmount copy() {
|
||||||
|
return new ReversePolarityAmount();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMessage() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ReversePolarityWatcher extends Watcher {
|
||||||
|
|
||||||
|
private final Map<UUID, Integer> artifactDamageReceivedThisTurn = new HashMap<>();
|
||||||
|
|
||||||
|
public ReversePolarityWatcher() {
|
||||||
|
super(ReversePolarityWatcher.class.getSimpleName(), WatcherScope.GAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReversePolarityWatcher(final ReversePolarityWatcher watcher) {
|
||||||
|
super(watcher);
|
||||||
|
for (Entry<UUID, Integer> entry : watcher.artifactDamageReceivedThisTurn.entrySet()) {
|
||||||
|
artifactDamageReceivedThisTurn.put(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void watch(GameEvent event, Game game) {
|
||||||
|
if (event.getType() == GameEvent.EventType.DAMAGED_PLAYER) {
|
||||||
|
UUID playerId = event.getTargetId();
|
||||||
|
if (playerId != null) {
|
||||||
|
Permanent permanent = game.getPermanent(event.getSourceId());
|
||||||
|
if (permanent != null && permanent.isArtifact()) {
|
||||||
|
artifactDamageReceivedThisTurn.putIfAbsent(playerId, 0);
|
||||||
|
artifactDamageReceivedThisTurn.compute(playerId, (k, v) -> v + event.getAmount());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getArtifactDamageReceivedThisTurn(UUID playerId) {
|
||||||
|
return artifactDamageReceivedThisTurn.getOrDefault(playerId, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reset() {
|
||||||
|
artifactDamageReceivedThisTurn.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ReversePolarityWatcher copy() {
|
||||||
|
return new ReversePolarityWatcher(this);
|
||||||
|
}
|
||||||
|
}
|
142
Mage.Sets/src/mage/cards/s/ShahOfNaarIsle.java
Normal file
142
Mage.Sets/src/mage/cards/s/ShahOfNaarIsle.java
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
/*
|
||||||
|
* 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.TriggeredAbilityImpl;
|
||||||
|
import mage.abilities.effects.OneShotEffect;
|
||||||
|
import mage.abilities.keyword.EchoAbility;
|
||||||
|
import mage.abilities.keyword.TrampleAbility;
|
||||||
|
import mage.cards.CardImpl;
|
||||||
|
import mage.cards.CardSetInfo;
|
||||||
|
import mage.constants.CardType;
|
||||||
|
import mage.constants.Outcome;
|
||||||
|
import mage.constants.SubType;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.game.events.GameEvent;
|
||||||
|
import mage.players.Player;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author LevelX2
|
||||||
|
*/
|
||||||
|
public class ShahOfNaarIsle extends CardImpl {
|
||||||
|
|
||||||
|
public ShahOfNaarIsle(UUID ownerId, CardSetInfo setInfo) {
|
||||||
|
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}");
|
||||||
|
|
||||||
|
this.subtype.add(SubType.EFREET);
|
||||||
|
this.power = new MageInt(6);
|
||||||
|
this.toughness = new MageInt(6);
|
||||||
|
|
||||||
|
// Trample
|
||||||
|
this.addAbility(TrampleAbility.getInstance());
|
||||||
|
|
||||||
|
// Echo {0}
|
||||||
|
this.addAbility(new EchoAbility("{0}"));
|
||||||
|
|
||||||
|
// When Shah of Naar Isle's echo cost is paid, each opponent may draw up to three cards.
|
||||||
|
this.addAbility(new ShahOfNaarIsleTriggeredAbility());
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShahOfNaarIsle(final ShahOfNaarIsle card) {
|
||||||
|
super(card);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ShahOfNaarIsle copy() {
|
||||||
|
return new ShahOfNaarIsle(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ShahOfNaarIsleTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
|
public ShahOfNaarIsleTriggeredAbility() {
|
||||||
|
super(Zone.BATTLEFIELD, new ShahOfNaarIsleEffect(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShahOfNaarIsleTriggeredAbility(final ShahOfNaarIsleTriggeredAbility effect) {
|
||||||
|
super(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkEventType(GameEvent event, Game game) {
|
||||||
|
return event.getType() == GameEvent.EventType.ECHO_PAID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkTrigger(GameEvent event, Game game) {
|
||||||
|
return getSourceId().equals(event.getSourceId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ShahOfNaarIsleTriggeredAbility copy() {
|
||||||
|
return new ShahOfNaarIsleTriggeredAbility(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRule() {
|
||||||
|
return "When {this}'s echo cost is paid, " + super.getRule();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ShahOfNaarIsleEffect extends OneShotEffect {
|
||||||
|
|
||||||
|
public ShahOfNaarIsleEffect() {
|
||||||
|
super(Outcome.DrawCard);
|
||||||
|
this.staticText = "each opponent may draw up to three cards";
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShahOfNaarIsleEffect(final ShahOfNaarIsleEffect effect) {
|
||||||
|
super(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ShahOfNaarIsleEffect copy() {
|
||||||
|
return new ShahOfNaarIsleEffect(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
Player controller = game.getPlayer(source.getControllerId());
|
||||||
|
if (controller != null) {
|
||||||
|
for (UUID playerId : game.getOpponents(controller.getId())) {
|
||||||
|
Player opponent = game.getPlayer(playerId);
|
||||||
|
if (opponent != null) {
|
||||||
|
int number = opponent.getAmount(0, 3, "Draw how many cards?", game);
|
||||||
|
opponent.drawCards(number, game);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -36,7 +36,7 @@ import mage.cards.CardImpl;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
import mage.constants.Outcome;
|
import mage.constants.Outcome;
|
||||||
import mage.filter.common.FilterCreaturePermanent;
|
import mage.filter.StaticFilters;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
|
@ -48,14 +48,12 @@ import mage.target.common.TargetCreatureOrPlayer;
|
||||||
*/
|
*/
|
||||||
public class Soulblast extends CardImpl {
|
public class Soulblast extends CardImpl {
|
||||||
|
|
||||||
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures you control");
|
|
||||||
|
|
||||||
public Soulblast(UUID ownerId, CardSetInfo setInfo) {
|
public Soulblast(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{3}{R}{R}{R}");
|
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{R}{R}{R}");
|
||||||
|
|
||||||
|
|
||||||
// As an additional cost to cast Soulblast, sacrifice all creatures you control.
|
// As an additional cost to cast Soulblast, sacrifice all creatures you control.
|
||||||
this.getSpellAbility().addCost(new SacrificeAllCost(filter));
|
this.getSpellAbility().addCost(new SacrificeAllCost(StaticFilters.FILTER_PERMANENT_CREATURES_CONTROLLED));
|
||||||
|
|
||||||
// Soulblast deals damage to target creature or player equal to the total power of the sacrificed creatures.
|
// Soulblast deals damage to target creature or player equal to the total power of the sacrificed creatures.
|
||||||
this.getSpellAbility().addEffect(new SoulblastEffect());
|
this.getSpellAbility().addEffect(new SoulblastEffect());
|
||||||
this.getSpellAbility().addTarget(new TargetCreatureOrPlayer());
|
this.getSpellAbility().addTarget(new TargetCreatureOrPlayer());
|
||||||
|
@ -90,7 +88,7 @@ class SoulblastEffect extends OneShotEffect {
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
int power = 0;
|
int power = 0;
|
||||||
for (Cost cost :source.getCosts()) {
|
for (Cost cost : source.getCosts()) {
|
||||||
if (cost instanceof SacrificeAllCost) {
|
if (cost instanceof SacrificeAllCost) {
|
||||||
for (Permanent permanent : ((SacrificeAllCost) cost).getPermanents()) {
|
for (Permanent permanent : ((SacrificeAllCost) cost).getPermanents()) {
|
||||||
power += permanent.getPower().getValue();
|
power += permanent.getPower().getValue();
|
||||||
|
|
83
Mage.Sets/src/mage/cards/s/SteamfloggerBoss.java
Normal file
83
Mage.Sets/src/mage/cards/s/SteamfloggerBoss.java
Normal 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.SimpleStaticAbility;
|
||||||
|
import mage.abilities.effects.Effect;
|
||||||
|
import mage.abilities.effects.common.InfoEffect;
|
||||||
|
import mage.abilities.effects.common.continuous.BoostControlledEffect;
|
||||||
|
import mage.abilities.effects.common.continuous.GainAbilityControlledEffect;
|
||||||
|
import mage.abilities.keyword.HasteAbility;
|
||||||
|
import mage.cards.CardImpl;
|
||||||
|
import mage.cards.CardSetInfo;
|
||||||
|
import mage.constants.CardType;
|
||||||
|
import mage.constants.Duration;
|
||||||
|
import mage.constants.SubType;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import mage.filter.common.FilterCreaturePermanent;
|
||||||
|
import static mage.filter.predicate.permanent.ControllerControlsIslandPredicate.filter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author LevelX2
|
||||||
|
*/
|
||||||
|
public class SteamfloggerBoss extends CardImpl {
|
||||||
|
|
||||||
|
public SteamfloggerBoss(UUID ownerId, CardSetInfo setInfo) {
|
||||||
|
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}");
|
||||||
|
|
||||||
|
this.subtype.add(SubType.GOBLIN);
|
||||||
|
this.subtype.add(SubType.RIGGER);
|
||||||
|
this.power = new MageInt(3);
|
||||||
|
this.toughness = new MageInt(3);
|
||||||
|
|
||||||
|
// Other Rigger creatures you control get +1/+0 and have haste.
|
||||||
|
Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD,
|
||||||
|
new BoostControlledEffect(1, 0, Duration.WhileOnBattlefield, new FilterCreaturePermanent(SubType.RIGGER, "Rigger creatures"), true));
|
||||||
|
Effect effect = new GainAbilityControlledEffect(HasteAbility.getInstance(), Duration.WhileOnBattlefield, filter);
|
||||||
|
effect.setText("and have haste");
|
||||||
|
ability.addEffect(effect);
|
||||||
|
this.addAbility(ability);
|
||||||
|
|
||||||
|
// If a Rigger you control would assemble a Contraption, it assembles two Contraptions instead.
|
||||||
|
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new InfoEffect("If a Rigger you control would assemble a Contraption, it assembles two Contraptions instead. (NOT IMPLEMENTED)")));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public SteamfloggerBoss(final SteamfloggerBoss card) {
|
||||||
|
super(card);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SteamfloggerBoss copy() {
|
||||||
|
return new SteamfloggerBoss(this);
|
||||||
|
}
|
||||||
|
}
|
|
@ -46,8 +46,7 @@ import mage.filter.FilterCard;
|
||||||
public class SultaiAscendancy extends CardImpl {
|
public class SultaiAscendancy extends CardImpl {
|
||||||
|
|
||||||
public SultaiAscendancy(UUID ownerId, CardSetInfo setInfo) {
|
public SultaiAscendancy(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{B}{G}{U}");
|
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{B}{G}{U}");
|
||||||
|
|
||||||
|
|
||||||
// At the beginning of your upkeep, look at the top two cards of your library. Put any number of them into your graveyard and the rest on top of your library in any order.
|
// At the beginning of your upkeep, look at the top two cards of your library. Put any number of them into your graveyard and the rest on top of your library in any order.
|
||||||
Effect effect = new LookLibraryAndPickControllerEffect(
|
Effect effect = new LookLibraryAndPickControllerEffect(
|
||||||
|
|
104
Mage.Sets/src/mage/cards/t/ThunderbladeCharge.java
Normal file
104
Mage.Sets/src/mage/cards/t/ThunderbladeCharge.java
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
/*
|
||||||
|
* 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.t;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.common.ControlledCreaturesDealCombatDamagePlayerTriggeredAbility;
|
||||||
|
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||||
|
import mage.abilities.effects.OneShotEffect;
|
||||||
|
import mage.abilities.effects.common.DamageTargetEffect;
|
||||||
|
import mage.abilities.effects.common.DoIfCostPaid;
|
||||||
|
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.game.Game;
|
||||||
|
import mage.players.Player;
|
||||||
|
import mage.target.common.TargetCreatureOrPlayer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author LevelX2
|
||||||
|
*/
|
||||||
|
public class ThunderbladeCharge extends CardImpl {
|
||||||
|
|
||||||
|
public ThunderbladeCharge(UUID ownerId, CardSetInfo setInfo) {
|
||||||
|
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{R}{R}");
|
||||||
|
|
||||||
|
// Thunderblade Charge deals 3 damage to target creature or player.
|
||||||
|
this.getSpellAbility().addEffect(new DamageTargetEffect(3));
|
||||||
|
this.getSpellAbility().addTarget(new TargetCreatureOrPlayer());
|
||||||
|
|
||||||
|
// Whenever one or more creatures you control deal combat damage to a player, if Thunderblade Charge is in your graveyard, you may pay {2}{R}{R}{R}. If you do, you may cast it without paying its mana cost.
|
||||||
|
this.addAbility(new ControlledCreaturesDealCombatDamagePlayerTriggeredAbility(Zone.GRAVEYARD,
|
||||||
|
new DoIfCostPaid(new ThunderbladeChargeCastEffect(), new ManaCostsImpl("{2}{R}{R}{R}"))
|
||||||
|
.setText("if {this} is in your graveyard, you may pay {2}{R}{R}{R}. If you do, you may cast it without paying its mana cost")));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ThunderbladeCharge(final ThunderbladeCharge card) {
|
||||||
|
super(card);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ThunderbladeCharge copy() {
|
||||||
|
return new ThunderbladeCharge(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ThunderbladeChargeCastEffect extends OneShotEffect {
|
||||||
|
|
||||||
|
public ThunderbladeChargeCastEffect() {
|
||||||
|
super(Outcome.PutCreatureInPlay);
|
||||||
|
this.staticText = "you may cast {this} without paying its mana cost";
|
||||||
|
}
|
||||||
|
|
||||||
|
public ThunderbladeChargeCastEffect(final ThunderbladeChargeCastEffect effect) {
|
||||||
|
super(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ThunderbladeChargeCastEffect copy() {
|
||||||
|
return new ThunderbladeChargeCastEffect(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
Player controller = game.getPlayer(source.getControllerId());
|
||||||
|
Card sourceCard = game.getCard(source.getSourceId());
|
||||||
|
if (controller != null
|
||||||
|
&& sourceCard != null
|
||||||
|
&& Zone.GRAVEYARD == game.getState().getZone(sourceCard.getId())) {
|
||||||
|
controller.cast(sourceCard.getSpellAbility(), game, true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -29,6 +29,7 @@ package mage.cards.t;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import mage.MageInt;
|
import mage.MageInt;
|
||||||
|
import mage.MageObject;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.TriggeredAbilityImpl;
|
import mage.abilities.TriggeredAbilityImpl;
|
||||||
import mage.abilities.effects.ContinuousEffectImpl;
|
import mage.abilities.effects.ContinuousEffectImpl;
|
||||||
|
@ -49,7 +50,7 @@ import mage.target.common.TargetOpponent;
|
||||||
public class TreacherousPitDweller extends CardImpl {
|
public class TreacherousPitDweller extends CardImpl {
|
||||||
|
|
||||||
public TreacherousPitDweller(UUID ownerId, CardSetInfo setInfo) {
|
public TreacherousPitDweller(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{B}{B}");
|
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}{B}");
|
||||||
this.subtype.add(SubType.DEMON);
|
this.subtype.add(SubType.DEMON);
|
||||||
|
|
||||||
this.power = new MageInt(4);
|
this.power = new MageInt(4);
|
||||||
|
@ -77,7 +78,7 @@ class TreacherousPitDwellerTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
private static final String ruleText = "When {this} enters the battlefield from a graveyard, ";
|
private static final String ruleText = "When {this} enters the battlefield from a graveyard, ";
|
||||||
|
|
||||||
public TreacherousPitDwellerTriggeredAbility() {
|
public TreacherousPitDwellerTriggeredAbility() {
|
||||||
super(Zone.BATTLEFIELD, new TreacherousPitDwellerEffect(),false);
|
super(Zone.BATTLEFIELD, new TreacherousPitDwellerEffect(), false);
|
||||||
addTarget(new TargetOpponent());
|
addTarget(new TargetOpponent());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,7 +93,7 @@ class TreacherousPitDwellerTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean checkTrigger(GameEvent event, Game game) {
|
public boolean checkTrigger(GameEvent event, Game game) {
|
||||||
return event.getTargetId().equals(getSourceId()) && ((EntersTheBattlefieldEvent) event).getFromZone() == Zone.GRAVEYARD;
|
return event.getTargetId().equals(getSourceId()) && ((EntersTheBattlefieldEvent) event).getFromZone() == Zone.GRAVEYARD;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -125,10 +126,12 @@ class TreacherousPitDwellerEffect extends ContinuousEffectImpl {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Permanent permanent = (Permanent) source.getSourceObjectIfItStillExists(game);
|
MageObject permanent = source.getSourceObjectIfItStillExists(game); // it can also return Card object
|
||||||
Player targetOpponent = game.getPlayer(source.getFirstTarget());
|
Player targetOpponent = game.getPlayer(source.getFirstTarget());
|
||||||
if (permanent != null && targetOpponent != null) {
|
if (permanent != null
|
||||||
return permanent.changeControllerId(targetOpponent.getId(), game);
|
&& (permanent instanceof Permanent)
|
||||||
|
&& targetOpponent != null) {
|
||||||
|
return ((Permanent) permanent).changeControllerId(targetOpponent.getId(), game);
|
||||||
} else {
|
} else {
|
||||||
discard();
|
discard();
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import mage.cards.CardSetInfo;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
import mage.constants.Duration;
|
import mage.constants.Duration;
|
||||||
import mage.target.common.TargetControlledCreaturePermanent;
|
import mage.target.common.TargetControlledCreaturePermanent;
|
||||||
|
import mage.target.common.TargetCreaturePermanent;
|
||||||
|
|
||||||
public class WickedReward extends CardImpl {
|
public class WickedReward extends CardImpl {
|
||||||
|
|
||||||
|
@ -19,6 +20,7 @@ public class WickedReward extends CardImpl {
|
||||||
|
|
||||||
//Target creature gets +4/+2 until end of turn.
|
//Target creature gets +4/+2 until end of turn.
|
||||||
this.getSpellAbility().addEffect(new BoostTargetEffect(4, 2, Duration.EndOfTurn));
|
this.getSpellAbility().addEffect(new BoostTargetEffect(4, 2, Duration.EndOfTurn));
|
||||||
|
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
|
||||||
}
|
}
|
||||||
|
|
||||||
public WickedReward(WickedReward other){
|
public WickedReward(WickedReward other){
|
||||||
|
|
|
@ -111,6 +111,7 @@ public class Antiquities extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Primal Clay", 26, Rarity.UNCOMMON, mage.cards.p.PrimalClay.class));
|
cards.add(new SetCardInfo("Primal Clay", 26, Rarity.UNCOMMON, mage.cards.p.PrimalClay.class));
|
||||||
cards.add(new SetCardInfo("Rakalite", 27, Rarity.UNCOMMON, mage.cards.r.Rakalite.class));
|
cards.add(new SetCardInfo("Rakalite", 27, Rarity.UNCOMMON, mage.cards.r.Rakalite.class));
|
||||||
cards.add(new SetCardInfo("Reconstruction", 56, Rarity.COMMON, mage.cards.r.Reconstruction.class));
|
cards.add(new SetCardInfo("Reconstruction", 56, Rarity.COMMON, mage.cards.r.Reconstruction.class));
|
||||||
|
cards.add(new SetCardInfo("Reverse Polarity", 100, Rarity.COMMON, mage.cards.r.ReversePolarity.class));
|
||||||
cards.add(new SetCardInfo("Rocket Launcher", 28, Rarity.UNCOMMON, mage.cards.r.RocketLauncher.class));
|
cards.add(new SetCardInfo("Rocket Launcher", 28, Rarity.UNCOMMON, mage.cards.r.RocketLauncher.class));
|
||||||
cards.add(new SetCardInfo("Sage of Lat-Nam", 57, Rarity.COMMON, mage.cards.s.SageOfLatNam.class));
|
cards.add(new SetCardInfo("Sage of Lat-Nam", 57, Rarity.COMMON, mage.cards.s.SageOfLatNam.class));
|
||||||
cards.add(new SetCardInfo("Shapeshifter", 29, Rarity.RARE, mage.cards.s.Shapeshifter.class));
|
cards.add(new SetCardInfo("Shapeshifter", 29, Rarity.RARE, mage.cards.s.Shapeshifter.class));
|
||||||
|
|
|
@ -142,6 +142,7 @@ public class FourthEdition extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Phantasmal Terrain", 89, Rarity.COMMON, mage.cards.p.PhantasmalTerrain.class));
|
cards.add(new SetCardInfo("Phantasmal Terrain", 89, Rarity.COMMON, mage.cards.p.PhantasmalTerrain.class));
|
||||||
cards.add(new SetCardInfo("Phantom Monster", 90, Rarity.UNCOMMON, mage.cards.p.PhantomMonster.class));
|
cards.add(new SetCardInfo("Phantom Monster", 90, Rarity.UNCOMMON, mage.cards.p.PhantomMonster.class));
|
||||||
cards.add(new SetCardInfo("Pirate Ship", 91, Rarity.RARE, mage.cards.p.PirateShip.class));
|
cards.add(new SetCardInfo("Pirate Ship", 91, Rarity.RARE, mage.cards.p.PirateShip.class));
|
||||||
|
cards.add(new SetCardInfo("Power Leak", 92, Rarity.COMMON, mage.cards.p.PowerLeak.class));
|
||||||
cards.add(new SetCardInfo("Power Sink", 93, Rarity.COMMON, mage.cards.p.PowerSink.class));
|
cards.add(new SetCardInfo("Power Sink", 93, Rarity.COMMON, mage.cards.p.PowerSink.class));
|
||||||
cards.add(new SetCardInfo("Prodigal Sorcerer", 94, Rarity.COMMON, mage.cards.p.ProdigalSorcerer.class));
|
cards.add(new SetCardInfo("Prodigal Sorcerer", 94, Rarity.COMMON, mage.cards.p.ProdigalSorcerer.class));
|
||||||
cards.add(new SetCardInfo("Psionic Entity", 95, Rarity.RARE, mage.cards.p.PsionicEntity.class));
|
cards.add(new SetCardInfo("Psionic Entity", 95, Rarity.RARE, mage.cards.p.PsionicEntity.class));
|
||||||
|
@ -263,6 +264,7 @@ public class FourthEdition extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Giant Strength", 196, Rarity.COMMON, mage.cards.g.GiantStrength.class));
|
cards.add(new SetCardInfo("Giant Strength", 196, Rarity.COMMON, mage.cards.g.GiantStrength.class));
|
||||||
cards.add(new SetCardInfo("Goblin Balloon Brigade", 197, Rarity.UNCOMMON, mage.cards.g.GoblinBalloonBrigade.class));
|
cards.add(new SetCardInfo("Goblin Balloon Brigade", 197, Rarity.UNCOMMON, mage.cards.g.GoblinBalloonBrigade.class));
|
||||||
cards.add(new SetCardInfo("Goblin King", 198, Rarity.RARE, mage.cards.g.GoblinKing.class));
|
cards.add(new SetCardInfo("Goblin King", 198, Rarity.RARE, mage.cards.g.GoblinKing.class));
|
||||||
|
cards.add(new SetCardInfo("Goblin Rock Sled", 199, Rarity.COMMON, mage.cards.g.GoblinRockSled.class));
|
||||||
cards.add(new SetCardInfo("Gray Ogre", 200, Rarity.COMMON, mage.cards.g.GrayOgre.class));
|
cards.add(new SetCardInfo("Gray Ogre", 200, Rarity.COMMON, mage.cards.g.GrayOgre.class));
|
||||||
cards.add(new SetCardInfo("Hill Giant", 201, Rarity.COMMON, mage.cards.h.HillGiant.class));
|
cards.add(new SetCardInfo("Hill Giant", 201, Rarity.COMMON, mage.cards.h.HillGiant.class));
|
||||||
cards.add(new SetCardInfo("Hurloon Minotaur", 202, Rarity.COMMON, mage.cards.h.HurloonMinotaur.class));
|
cards.add(new SetCardInfo("Hurloon Minotaur", 202, Rarity.COMMON, mage.cards.h.HurloonMinotaur.class));
|
||||||
|
|
|
@ -171,6 +171,7 @@ public class FutureSight extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Petrified Plating", 133, Rarity.COMMON, mage.cards.p.PetrifiedPlating.class));
|
cards.add(new SetCardInfo("Petrified Plating", 133, Rarity.COMMON, mage.cards.p.PetrifiedPlating.class));
|
||||||
cards.add(new SetCardInfo("Phosphorescent Feast", 149, Rarity.UNCOMMON, mage.cards.p.PhosphorescentFeast.class));
|
cards.add(new SetCardInfo("Phosphorescent Feast", 149, Rarity.UNCOMMON, mage.cards.p.PhosphorescentFeast.class));
|
||||||
cards.add(new SetCardInfo("Pooling Venom", 74, Rarity.UNCOMMON, mage.cards.p.PoolingVenom.class));
|
cards.add(new SetCardInfo("Pooling Venom", 74, Rarity.UNCOMMON, mage.cards.p.PoolingVenom.class));
|
||||||
|
cards.add(new SetCardInfo("Putrid Cyclops", 75, Rarity.COMMON, mage.cards.p.PutridCyclops.class));
|
||||||
cards.add(new SetCardInfo("Pyromancer's Swath", 104, Rarity.RARE, mage.cards.p.PyromancersSwath.class));
|
cards.add(new SetCardInfo("Pyromancer's Swath", 104, Rarity.RARE, mage.cards.p.PyromancersSwath.class));
|
||||||
cards.add(new SetCardInfo("Quagnoth", 150, Rarity.RARE, mage.cards.q.Quagnoth.class));
|
cards.add(new SetCardInfo("Quagnoth", 150, Rarity.RARE, mage.cards.q.Quagnoth.class));
|
||||||
cards.add(new SetCardInfo("Quiet Disrepair", 134, Rarity.COMMON, mage.cards.q.QuietDisrepair.class));
|
cards.add(new SetCardInfo("Quiet Disrepair", 134, Rarity.COMMON, mage.cards.q.QuietDisrepair.class));
|
||||||
|
@ -189,6 +190,7 @@ public class FutureSight extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Scout's Warning", 16, Rarity.RARE, mage.cards.s.ScoutsWarning.class));
|
cards.add(new SetCardInfo("Scout's Warning", 16, Rarity.RARE, mage.cards.s.ScoutsWarning.class));
|
||||||
cards.add(new SetCardInfo("Second Wind", 57, Rarity.UNCOMMON, mage.cards.s.SecondWind.class));
|
cards.add(new SetCardInfo("Second Wind", 57, Rarity.UNCOMMON, mage.cards.s.SecondWind.class));
|
||||||
cards.add(new SetCardInfo("Seht's Tiger", 31, Rarity.RARE, mage.cards.s.SehtsTiger.class));
|
cards.add(new SetCardInfo("Seht's Tiger", 31, Rarity.RARE, mage.cards.s.SehtsTiger.class));
|
||||||
|
cards.add(new SetCardInfo("Shah of Naar Isle", 119, Rarity.RARE, mage.cards.s.ShahOfNaarIsle.class));
|
||||||
cards.add(new SetCardInfo("Shapeshifter's Marrow", 58, Rarity.RARE, mage.cards.s.ShapeshiftersMarrow.class));
|
cards.add(new SetCardInfo("Shapeshifter's Marrow", 58, Rarity.RARE, mage.cards.s.ShapeshiftersMarrow.class));
|
||||||
cards.add(new SetCardInfo("Shimian Specter", 76, Rarity.RARE, mage.cards.s.ShimianSpecter.class));
|
cards.add(new SetCardInfo("Shimian Specter", 76, Rarity.RARE, mage.cards.s.ShimianSpecter.class));
|
||||||
cards.add(new SetCardInfo("Shivan Sand-Mage", 108, Rarity.UNCOMMON, mage.cards.s.ShivanSandMage.class));
|
cards.add(new SetCardInfo("Shivan Sand-Mage", 108, Rarity.UNCOMMON, mage.cards.s.ShivanSandMage.class));
|
||||||
|
@ -206,6 +208,7 @@ public class FutureSight extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Spirit en-Dal", 17, Rarity.UNCOMMON, mage.cards.s.SpiritEnDal.class));
|
cards.add(new SetCardInfo("Spirit en-Dal", 17, Rarity.UNCOMMON, mage.cards.s.SpiritEnDal.class));
|
||||||
cards.add(new SetCardInfo("Sporoloth Ancient", 152, Rarity.COMMON, mage.cards.s.SporolothAncient.class));
|
cards.add(new SetCardInfo("Sporoloth Ancient", 152, Rarity.COMMON, mage.cards.s.SporolothAncient.class));
|
||||||
cards.add(new SetCardInfo("Sprout Swarm", 138, Rarity.COMMON, mage.cards.s.SproutSwarm.class));
|
cards.add(new SetCardInfo("Sprout Swarm", 138, Rarity.COMMON, mage.cards.s.SproutSwarm.class));
|
||||||
|
cards.add(new SetCardInfo("Steamflogger Boss", 121, Rarity.RARE, mage.cards.s.SteamfloggerBoss.class));
|
||||||
cards.add(new SetCardInfo("Storm Entity", 122, Rarity.UNCOMMON, mage.cards.s.StormEntity.class));
|
cards.add(new SetCardInfo("Storm Entity", 122, Rarity.UNCOMMON, mage.cards.s.StormEntity.class));
|
||||||
cards.add(new SetCardInfo("Street Wraith", 90, Rarity.UNCOMMON, mage.cards.s.StreetWraith.class));
|
cards.add(new SetCardInfo("Street Wraith", 90, Rarity.UNCOMMON, mage.cards.s.StreetWraith.class));
|
||||||
cards.add(new SetCardInfo("Stronghold Rats", 79, Rarity.UNCOMMON, mage.cards.s.StrongholdRats.class));
|
cards.add(new SetCardInfo("Stronghold Rats", 79, Rarity.UNCOMMON, mage.cards.s.StrongholdRats.class));
|
||||||
|
@ -215,6 +218,7 @@ public class FutureSight extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Tarmogoyf", 153, Rarity.RARE, mage.cards.t.Tarmogoyf.class));
|
cards.add(new SetCardInfo("Tarmogoyf", 153, Rarity.RARE, mage.cards.t.Tarmogoyf.class));
|
||||||
cards.add(new SetCardInfo("Tarox Bladewing", 123, Rarity.RARE, mage.cards.t.TaroxBladewing.class));
|
cards.add(new SetCardInfo("Tarox Bladewing", 123, Rarity.RARE, mage.cards.t.TaroxBladewing.class));
|
||||||
cards.add(new SetCardInfo("Thornweald Archer", 154, Rarity.COMMON, mage.cards.t.ThornwealdArcher.class));
|
cards.add(new SetCardInfo("Thornweald Archer", 154, Rarity.COMMON, mage.cards.t.ThornwealdArcher.class));
|
||||||
|
cards.add(new SetCardInfo("Thunderblade Charge", 124, Rarity.RARE, mage.cards.t.ThunderbladeCharge.class));
|
||||||
cards.add(new SetCardInfo("Tolaria West", 173, Rarity.UNCOMMON, mage.cards.t.TolariaWest.class));
|
cards.add(new SetCardInfo("Tolaria West", 173, Rarity.UNCOMMON, mage.cards.t.TolariaWest.class));
|
||||||
cards.add(new SetCardInfo("Tombstalker", 91, Rarity.RARE, mage.cards.t.Tombstalker.class));
|
cards.add(new SetCardInfo("Tombstalker", 91, Rarity.RARE, mage.cards.t.Tombstalker.class));
|
||||||
cards.add(new SetCardInfo("Unblinking Bleb", 45, Rarity.COMMON, mage.cards.u.UnblinkingBleb.class));
|
cards.add(new SetCardInfo("Unblinking Bleb", 45, Rarity.COMMON, mage.cards.u.UnblinkingBleb.class));
|
||||||
|
|
|
@ -209,6 +209,7 @@ public class LimitedEditionAlpha extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Plains", 285, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Plains", 285, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Plains", 286, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Plains", 286, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Plateau", 287, Rarity.RARE, mage.cards.p.Plateau.class));
|
cards.add(new SetCardInfo("Plateau", 287, Rarity.RARE, mage.cards.p.Plateau.class));
|
||||||
|
cards.add(new SetCardInfo("Power Leak", 72, Rarity.COMMON, mage.cards.p.PowerLeak.class));
|
||||||
cards.add(new SetCardInfo("Power Sink", 73, Rarity.COMMON, mage.cards.p.PowerSink.class));
|
cards.add(new SetCardInfo("Power Sink", 73, Rarity.COMMON, mage.cards.p.PowerSink.class));
|
||||||
cards.add(new SetCardInfo("Power Surge", 168, Rarity.RARE, mage.cards.p.PowerSurge.class));
|
cards.add(new SetCardInfo("Power Surge", 168, Rarity.RARE, mage.cards.p.PowerSurge.class));
|
||||||
cards.add(new SetCardInfo("Prodigal Sorcerer", 74, Rarity.COMMON, mage.cards.p.ProdigalSorcerer.class));
|
cards.add(new SetCardInfo("Prodigal Sorcerer", 74, Rarity.COMMON, mage.cards.p.ProdigalSorcerer.class));
|
||||||
|
|
|
@ -214,6 +214,7 @@ public class LimitedEditionBeta extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Plains", 289, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Plains", 289, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Plains", 290, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Plains", 290, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Plateau", 280, Rarity.RARE, mage.cards.p.Plateau.class));
|
cards.add(new SetCardInfo("Plateau", 280, Rarity.RARE, mage.cards.p.Plateau.class));
|
||||||
|
cards.add(new SetCardInfo("Power Leak", 72, Rarity.COMMON, mage.cards.p.PowerLeak.class));
|
||||||
cards.add(new SetCardInfo("Power Sink", 73, Rarity.COMMON, mage.cards.p.PowerSink.class));
|
cards.add(new SetCardInfo("Power Sink", 73, Rarity.COMMON, mage.cards.p.PowerSink.class));
|
||||||
cards.add(new SetCardInfo("Power Surge", 168, Rarity.RARE, mage.cards.p.PowerSurge.class));
|
cards.add(new SetCardInfo("Power Surge", 168, Rarity.RARE, mage.cards.p.PowerSurge.class));
|
||||||
cards.add(new SetCardInfo("Prodigal Sorcerer", 74, Rarity.COMMON, mage.cards.p.ProdigalSorcerer.class));
|
cards.add(new SetCardInfo("Prodigal Sorcerer", 74, Rarity.COMMON, mage.cards.p.ProdigalSorcerer.class));
|
||||||
|
|
|
@ -27,9 +27,7 @@
|
||||||
*/
|
*/
|
||||||
package mage.sets;
|
package mage.sets;
|
||||||
|
|
||||||
import mage.cards.CardGraphicInfo;
|
|
||||||
import mage.cards.ExpansionSet;
|
import mage.cards.ExpansionSet;
|
||||||
import mage.cards.FrameStyle;
|
|
||||||
import mage.constants.Rarity;
|
import mage.constants.Rarity;
|
||||||
import mage.constants.SetType;
|
import mage.constants.SetType;
|
||||||
|
|
||||||
|
@ -50,7 +48,6 @@ public class MasterpieceSeriesAmonkhet extends ExpansionSet {
|
||||||
this.blockName = "Masterpiece Series";
|
this.blockName = "Masterpiece Series";
|
||||||
this.hasBoosters = false;
|
this.hasBoosters = false;
|
||||||
this.hasBasicLands = false;
|
this.hasBasicLands = false;
|
||||||
CardGraphicInfo cardGraphicInfo = new CardGraphicInfo(FrameStyle.KLD_INVENTION, false);
|
|
||||||
|
|
||||||
cards.add(new SetCardInfo("Aggravated Assault", 25, Rarity.SPECIAL, mage.cards.a.AggravatedAssault.class));
|
cards.add(new SetCardInfo("Aggravated Assault", 25, Rarity.SPECIAL, mage.cards.a.AggravatedAssault.class));
|
||||||
cards.add(new SetCardInfo("Armageddon", 31, Rarity.SPECIAL, mage.cards.a.Armageddon.class));
|
cards.add(new SetCardInfo("Armageddon", 31, Rarity.SPECIAL, mage.cards.a.Armageddon.class));
|
||||||
|
|
|
@ -220,6 +220,7 @@ public class RevisedEdition extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Plains", 294, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Plains", 294, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Plains", 295, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Plains", 295, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Plateau", 296, Rarity.RARE, mage.cards.p.Plateau.class));
|
cards.add(new SetCardInfo("Plateau", 296, Rarity.RARE, mage.cards.p.Plateau.class));
|
||||||
|
cards.add(new SetCardInfo("Power Leak", 73, Rarity.COMMON, mage.cards.p.PowerLeak.class));
|
||||||
cards.add(new SetCardInfo("Power Sink", 74, Rarity.COMMON, mage.cards.p.PowerSink.class));
|
cards.add(new SetCardInfo("Power Sink", 74, Rarity.COMMON, mage.cards.p.PowerSink.class));
|
||||||
cards.add(new SetCardInfo("Power Surge", 169, Rarity.RARE, mage.cards.p.PowerSurge.class));
|
cards.add(new SetCardInfo("Power Surge", 169, Rarity.RARE, mage.cards.p.PowerSurge.class));
|
||||||
cards.add(new SetCardInfo("Primal Clay", 271, Rarity.RARE, mage.cards.p.PrimalClay.class));
|
cards.add(new SetCardInfo("Primal Clay", 271, Rarity.RARE, mage.cards.p.PrimalClay.class));
|
||||||
|
@ -234,6 +235,7 @@ public class RevisedEdition extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Regrowth", 121, Rarity.UNCOMMON, mage.cards.r.Regrowth.class));
|
cards.add(new SetCardInfo("Regrowth", 121, Rarity.UNCOMMON, mage.cards.r.Regrowth.class));
|
||||||
cards.add(new SetCardInfo("Resurrection", 218, Rarity.UNCOMMON, mage.cards.r.Resurrection.class));
|
cards.add(new SetCardInfo("Resurrection", 218, Rarity.UNCOMMON, mage.cards.r.Resurrection.class));
|
||||||
cards.add(new SetCardInfo("Reverse Damage", 219, Rarity.RARE, mage.cards.r.ReverseDamage.class));
|
cards.add(new SetCardInfo("Reverse Damage", 219, Rarity.RARE, mage.cards.r.ReverseDamage.class));
|
||||||
|
cards.add(new SetCardInfo("Reverse Polarity", 220, Rarity.UNCOMMON, mage.cards.r.ReversePolarity.class));
|
||||||
cards.add(new SetCardInfo("Righteousness", 221, Rarity.RARE, mage.cards.r.Righteousness.class));
|
cards.add(new SetCardInfo("Righteousness", 221, Rarity.RARE, mage.cards.r.Righteousness.class));
|
||||||
cards.add(new SetCardInfo("Roc of Kher Ridges", 171, Rarity.RARE, mage.cards.r.RocOfKherRidges.class));
|
cards.add(new SetCardInfo("Roc of Kher Ridges", 171, Rarity.RARE, mage.cards.r.RocOfKherRidges.class));
|
||||||
cards.add(new SetCardInfo("Rock Hydra", 172, Rarity.RARE, mage.cards.r.RockHydra.class));
|
cards.add(new SetCardInfo("Rock Hydra", 172, Rarity.RARE, mage.cards.r.RockHydra.class));
|
||||||
|
|
|
@ -214,6 +214,7 @@ public class UnlimitedEdition extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Plains", 290, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Plains", 290, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Plains", 291, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Plains", 291, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Plateau", 292, Rarity.RARE, mage.cards.p.Plateau.class));
|
cards.add(new SetCardInfo("Plateau", 292, Rarity.RARE, mage.cards.p.Plateau.class));
|
||||||
|
cards.add(new SetCardInfo("Power Leak", 72, Rarity.COMMON, mage.cards.p.PowerLeak.class));
|
||||||
cards.add(new SetCardInfo("Power Sink", 73, Rarity.COMMON, mage.cards.p.PowerSink.class));
|
cards.add(new SetCardInfo("Power Sink", 73, Rarity.COMMON, mage.cards.p.PowerSink.class));
|
||||||
cards.add(new SetCardInfo("Power Surge", 168, Rarity.RARE, mage.cards.p.PowerSurge.class));
|
cards.add(new SetCardInfo("Power Surge", 168, Rarity.RARE, mage.cards.p.PowerSurge.class));
|
||||||
cards.add(new SetCardInfo("Prodigal Sorcerer", 74, Rarity.COMMON, mage.cards.p.ProdigalSorcerer.class));
|
cards.add(new SetCardInfo("Prodigal Sorcerer", 74, Rarity.COMMON, mage.cards.p.ProdigalSorcerer.class));
|
||||||
|
|
|
@ -75,6 +75,7 @@ public class Unstable extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Plains", 212, Rarity.LAND, mage.cards.basiclands.Plains.class, new CardGraphicInfo(FrameStyle.UNH_FULL_ART_BASIC, false)));
|
cards.add(new SetCardInfo("Plains", 212, Rarity.LAND, mage.cards.basiclands.Plains.class, new CardGraphicInfo(FrameStyle.UNH_FULL_ART_BASIC, false)));
|
||||||
cards.add(new SetCardInfo("Snickering Squirrel", 68, Rarity.COMMON, mage.cards.s.SnickeringSquirrel.class));
|
cards.add(new SetCardInfo("Snickering Squirrel", 68, Rarity.COMMON, mage.cards.s.SnickeringSquirrel.class));
|
||||||
cards.add(new SetCardInfo("Squirrel-Powered Scheme", 70, Rarity.UNCOMMON, mage.cards.s.SquirrelPoweredScheme.class));
|
cards.add(new SetCardInfo("Squirrel-Powered Scheme", 70, Rarity.UNCOMMON, mage.cards.s.SquirrelPoweredScheme.class));
|
||||||
|
cards.add(new SetCardInfo("Steamflogger Boss", 93, Rarity.RARE, mage.cards.s.SteamfloggerBoss.class));
|
||||||
cards.add(new SetCardInfo("Steel Squirrel", 162, Rarity.UNCOMMON, mage.cards.s.SteelSquirrel.class));
|
cards.add(new SetCardInfo("Steel Squirrel", 162, Rarity.UNCOMMON, mage.cards.s.SteelSquirrel.class));
|
||||||
cards.add(new SetCardInfo("Summon the Pack", 74, Rarity.MYTHIC, mage.cards.s.SummonThePack.class));
|
cards.add(new SetCardInfo("Summon the Pack", 74, Rarity.MYTHIC, mage.cards.s.SummonThePack.class));
|
||||||
cards.add(new SetCardInfo("Swamp", 214, Rarity.LAND, mage.cards.basiclands.Swamp.class, new CardGraphicInfo(FrameStyle.UNH_FULL_ART_BASIC, false)));
|
cards.add(new SetCardInfo("Swamp", 214, Rarity.LAND, mage.cards.basiclands.Swamp.class, new CardGraphicInfo(FrameStyle.UNH_FULL_ART_BASIC, false)));
|
||||||
|
|
|
@ -27,9 +27,9 @@
|
||||||
*/
|
*/
|
||||||
package org.mage.test.cards.abilities.keywords;
|
package org.mage.test.cards.abilities.keywords;
|
||||||
|
|
||||||
|
import mage.abilities.keyword.TrampleAbility;
|
||||||
import mage.constants.PhaseStep;
|
import mage.constants.PhaseStep;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
import org.junit.Ignore;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
|
|
||||||
|
@ -39,6 +39,27 @@ import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
*/
|
*/
|
||||||
public class FlashbackTest extends CardTestPlayerBase {
|
public class FlashbackTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNormalWildHunger() {
|
||||||
|
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4);
|
||||||
|
|
||||||
|
// Target creature gets +3/+1 and gains trample until end of turn.
|
||||||
|
// Flashback {3}{R}
|
||||||
|
addCard(Zone.GRAVEYARD, playerA, "Wild Hunger");
|
||||||
|
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 1);
|
||||||
|
|
||||||
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Flashback", "Silvercoat Lion");
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertPowerToughness(playerA, "Silvercoat Lion", 5, 3);
|
||||||
|
assertAbility(playerA, "Silvercoat Lion", TrampleAbility.getInstance(), true);
|
||||||
|
assertExileCount("Wild Hunger", 1);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fracturing Gust is bugged. In a match against Affinity, it worked
|
* Fracturing Gust is bugged. In a match against Affinity, it worked
|
||||||
* properly when cast from hand. When I cast it from graveyard c/o
|
* properly when cast from hand. When I cast it from graveyard c/o
|
||||||
|
@ -219,7 +240,7 @@ public class FlashbackTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
// Conflagrate deals X damage divided as you choose among any number of target creatures and/or players.
|
// Conflagrate deals X damage divided as you choose among any number of target creatures and/or players.
|
||||||
// Flashback-{R}{R}, Discard X cards.
|
// Flashback-{R}{R}, Discard X cards.
|
||||||
addCard(Zone.HAND, playerA, "Conflagrate", 1);
|
addCard(Zone.HAND, playerA, "Conflagrate", 1); // Sorcery {X}{X}{R}
|
||||||
|
|
||||||
addCard(Zone.HAND, playerA, "Forest", 4);
|
addCard(Zone.HAND, playerA, "Forest", 4);
|
||||||
|
|
||||||
|
@ -307,20 +328,26 @@ public class FlashbackTest extends CardTestPlayerBase {
|
||||||
public void testAltarsReap() {
|
public void testAltarsReap() {
|
||||||
|
|
||||||
addCard(Zone.LIBRARY, playerA, "Island", 2);
|
addCard(Zone.LIBRARY, playerA, "Island", 2);
|
||||||
addCard(Zone.GRAVEYARD, playerA, "Altar's Reap", 1);
|
// As an additional cost to cast Altar's Reap, sacrifice a creature.
|
||||||
|
// Draw two cards.
|
||||||
|
addCard(Zone.GRAVEYARD, playerA, "Altar's Reap", 1); // Instant {1}{B}
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Underground Sea", 4);
|
addCard(Zone.BATTLEFIELD, playerA, "Underground Sea", 4);
|
||||||
addCard(Zone.HAND, playerA, "Snapcaster Mage", 1);
|
addCard(Zone.HAND, playerA, "Snapcaster Mage", 1);
|
||||||
|
|
||||||
|
// Flash
|
||||||
|
// When Snapcaster Mage enters the battlefield, target instant or sorcery card in your graveyard gains flashback until end of turn.
|
||||||
|
// The flashback cost is equal to its mana cost.
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Snapcaster Mage");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Snapcaster Mage");
|
||||||
setChoice(playerA, "Altar's Reap");
|
setChoice(playerA, "Altar's Reap");
|
||||||
|
|
||||||
activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Flashback {1}{B}");
|
activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Flashback");
|
||||||
setChoice(playerA, "Snapcaster Mage");
|
setChoice(playerA, "Snapcaster Mage");
|
||||||
|
|
||||||
setStopAt(1, PhaseStep.END_TURN);
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
execute();
|
execute();
|
||||||
|
|
||||||
assertGraveyardCount(playerA, "Snapcaster Mage", 1);
|
assertGraveyardCount(playerA, "Snapcaster Mage", 1);
|
||||||
|
assertExileCount(playerA, "Altar's Reap", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -520,7 +547,6 @@ public class FlashbackTest extends CardTestPlayerBase {
|
||||||
* to a spell, and the flashback cost is already an alternative cost.
|
* to a spell, and the flashback cost is already an alternative cost.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
@Ignore
|
|
||||||
public void testSnapcasterMageSpellWithAlternateCost() {
|
public void testSnapcasterMageSpellWithAlternateCost() {
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 1);
|
addCard(Zone.BATTLEFIELD, playerA, "Forest", 1);
|
||||||
|
|
|
@ -111,4 +111,47 @@ public class MimicVatTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Player A has Mimic Vat and plays Sidisi, Undead Vizier and exploits.
|
||||||
|
* Player N responds to Mimic Vat Trigger with Shred Memory, exiling Sidisi.
|
||||||
|
* Sidisi gets exiled but then xmage allows player A to imprint the
|
||||||
|
* creature, which shouldn't be possible.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void TestExileFails() {
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1);
|
||||||
|
// Imprint - Whenever a nontoken creature dies, you may exile that card. If you do, return each other card exiled with Mimic Vat to its owner's graveyard.
|
||||||
|
// {3}, {T}: Create a token that's a copy of a card exiled with Mimic Vat. It gains haste. Exile it at the beginning of the next end step.
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Mimic Vat", 1); // Artifact {3}
|
||||||
|
|
||||||
|
addCard(Zone.HAND, playerA, "Lightning Bolt", 1);
|
||||||
|
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Swamp", 2);
|
||||||
|
// Exile up to four target cards from a single graveyard.
|
||||||
|
// Transmute {1}{B}{B}
|
||||||
|
addCard(Zone.HAND, playerB, "Shred Memory", 1); // Instant {1}{B}
|
||||||
|
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "Silvercoat Lion");
|
||||||
|
setChoice(playerA, "Yes");
|
||||||
|
setChoice(playerA, "Silvercoat Lion");
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Shred Memory", "Silvercoat Lion", "Whenever a nontoken creature dies");
|
||||||
|
setChoice(playerA, "Yes");
|
||||||
|
|
||||||
|
activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "{3}, {T}: Create a token that's a copy of a card exiled with ");
|
||||||
|
setChoice(playerA, "Yes");
|
||||||
|
setChoice(playerA, "Silvercoat Lion");
|
||||||
|
|
||||||
|
setStopAt(3, PhaseStep.BEGIN_COMBAT);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertGraveyardCount(playerA, "Lightning Bolt", 1);
|
||||||
|
assertGraveyardCount(playerB, "Shred Memory", 1);
|
||||||
|
|
||||||
|
assertExileCount(playerB, "Silvercoat Lion", 1);
|
||||||
|
assertPermanentCount(playerA, "Silvercoat Lion", 0);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,12 +86,12 @@ public class SpreadingSeasTest extends CardTestPlayerBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUtopiaSprawlWithSpreadingSeas(){
|
public void testUtopiaSprawlWithSpreadingSeas() {
|
||||||
addCard(Zone.HAND, playerA, "Spreading Seas", 1);
|
addCard(Zone.HAND, playerA, "Spreading Seas", 1);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 1);
|
addCard(Zone.BATTLEFIELD, playerA, "Forest", 1);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 10);
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 10);
|
||||||
addCard(Zone.HAND, playerA, "Utopia Sprawl");
|
addCard(Zone.HAND, playerA, "Utopia Sprawl");
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Utopia Sprawl","Forest");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Utopia Sprawl", "Forest");
|
||||||
setChoice(playerA, "Green");
|
setChoice(playerA, "Green");
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Spreading Seas", "Forest");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Spreading Seas", "Forest");
|
||||||
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
|
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||||
|
@ -99,9 +99,8 @@ public class SpreadingSeasTest extends CardTestPlayerBase {
|
||||||
assertNotSubtype("Forest", SubType.FOREST);
|
assertNotSubtype("Forest", SubType.FOREST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSpreadingSeasWithUrzaLand(){
|
public void testSpreadingSeasWithUrzaLand() {
|
||||||
addCard(Zone.HAND, playerA, "Spreading Seas", 1);
|
addCard(Zone.HAND, playerA, "Spreading Seas", 1);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Urza's Tower", 1);
|
addCard(Zone.BATTLEFIELD, playerA, "Urza's Tower", 1);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 10);
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 10);
|
||||||
|
@ -111,4 +110,40 @@ public class SpreadingSeasTest extends CardTestPlayerBase {
|
||||||
assertNotSubtype("Urza's Tower", SubType.URZAS);
|
assertNotSubtype("Urza's Tower", SubType.URZAS);
|
||||||
assertNotSubtype("Urza's Tower", SubType.TOWER);
|
assertNotSubtype("Urza's Tower", SubType.TOWER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://github.com/magefree/mage/issues/4529 Some spell effects that
|
||||||
|
* effect the use of mana abilities on lands are inoperative. Example
|
||||||
|
* Spreading Seas transforms enchanted land into an island and it loses all
|
||||||
|
* other abilities. The AI does not recognize this and is able to use all
|
||||||
|
* abilities of the enchanted land including all previous mana abilities and
|
||||||
|
* activated abilities, in addition to now also being an island due to
|
||||||
|
* Spreading Sea's effect.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testSpreadingRemovesOtherAbilities() {
|
||||||
|
|
||||||
|
// Enchant land
|
||||||
|
// When Spreading Seas enters the battlefield, draw a card.
|
||||||
|
// Enchanted land is an Island.
|
||||||
|
addCard(Zone.HAND, playerA, "Spreading Seas", 1); // ENCHANTMENT {1}{U}
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 2);
|
||||||
|
|
||||||
|
// {T}: Add {C} to your mana pool.
|
||||||
|
// {1}{R}, {T}: Create a 0/1 red Kobold creature token named Kobolds of Kher Keep.
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Kher Keep", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Mountain", 2);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Spreading Seas", "Kher Keep");
|
||||||
|
activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "{1}{R}"); // Ability should not be available
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertPermanentCount(playerA, "Spreading Seas", 1);
|
||||||
|
|
||||||
|
assertPermanentCount(playerB, "Kobolds of Kher Keep", 0);
|
||||||
|
assertTapped("Kher Keep", false);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,24 +27,24 @@
|
||||||
*/
|
*/
|
||||||
package org.mage.test.serverside.deck;
|
package org.mage.test.serverside.deck;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import mage.cards.decks.Deck;
|
import mage.cards.decks.Deck;
|
||||||
import mage.cards.decks.DeckValidator;
|
import mage.cards.decks.DeckValidator;
|
||||||
import mage.cards.repository.CardInfo;
|
import mage.cards.repository.CardInfo;
|
||||||
import mage.cards.repository.CardRepository;
|
import mage.cards.repository.CardRepository;
|
||||||
import mage.deck.Limited;
|
import mage.deck.Limited;
|
||||||
import mage.deck.Modern;
|
import mage.deck.Modern;
|
||||||
|
import mage.deck.Standard;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
import org.mage.test.serverside.base.MageTestBase;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author LevelX2
|
* @author LevelX2
|
||||||
*/
|
*/
|
||||||
public class DeckValidatorTest extends CardTestPlayerBase {
|
public class DeckValidatorTest extends MageTestBase {
|
||||||
|
|
||||||
static class CardNameAmount {
|
static class CardNameAmount {
|
||||||
|
|
||||||
|
@ -84,6 +84,38 @@ public class DeckValidatorTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStandardValid() {
|
||||||
|
ArrayList<CardNameAmount> deck = new ArrayList<>();
|
||||||
|
|
||||||
|
deck.add(new CardNameAmount("MPS-AKH", 28, 4)); // Rhonas the Indomitable
|
||||||
|
deck.add(new CardNameAmount("Built to Smash", 4));
|
||||||
|
deck.add(new CardNameAmount("Heroic Intervention", 4));
|
||||||
|
deck.add(new CardNameAmount("Mountain", 48));
|
||||||
|
|
||||||
|
DeckValidator validator = new Standard();
|
||||||
|
boolean validationSuccessful = testDeckValid(validator, deck);
|
||||||
|
Assert.assertTrue(validator.getInvalid().toString(), validationSuccessful);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStandardNotValid() {
|
||||||
|
ArrayList<CardNameAmount> deck = new ArrayList<>();
|
||||||
|
|
||||||
|
deck.add(new CardNameAmount("MPS-AKH", 28, 4)); // Rhonas the Indomitable
|
||||||
|
deck.add(new CardNameAmount("Built to Smash", 4));
|
||||||
|
deck.add(new CardNameAmount("Heroic Intervention", 4));
|
||||||
|
deck.add(new CardNameAmount("Mountain", 47));
|
||||||
|
|
||||||
|
ArrayList<CardNameAmount> sideboard = new ArrayList<>();
|
||||||
|
sideboard.add(new CardNameAmount("Mountain", 16));
|
||||||
|
|
||||||
|
DeckValidator validator = new Standard();
|
||||||
|
testDeckValid(validator, deck, sideboard);
|
||||||
|
Assert.assertEquals("invalid message not correct",
|
||||||
|
"{Sideboard=Must contain no more than 15 cards : has 16 cards, Deck=Must contain at least 60 cards: has only 59 cards}", validator.getInvalid().toString());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLimitedValid() {
|
public void testLimitedValid() {
|
||||||
ArrayList<CardNameAmount> deck = new ArrayList<>();
|
ArrayList<CardNameAmount> deck = new ArrayList<>();
|
||||||
|
@ -226,37 +258,156 @@ public class DeckValidatorTest extends CardTestPlayerBase {
|
||||||
@Test
|
@Test
|
||||||
public void testModernBanned() {
|
public void testModernBanned() {
|
||||||
ArrayList<CardNameAmount> deckList = new ArrayList<>();
|
ArrayList<CardNameAmount> deckList = new ArrayList<>();
|
||||||
|
DeckValidator validator = new Modern();
|
||||||
|
|
||||||
deckList.add(new CardNameAmount("Ancestral Vision", 4));
|
deckList.add(new CardNameAmount("Ancestral Vision", 4));
|
||||||
|
deckList.add(new CardNameAmount("Mountain", 56));
|
||||||
|
boolean validationSuccessful = testDeckValid(validator, deckList);
|
||||||
|
Assert.assertTrue(validator.getInvalid().toString(), validationSuccessful);
|
||||||
|
validator.getInvalid().clear();
|
||||||
|
|
||||||
|
deckList.clear();
|
||||||
deckList.add(new CardNameAmount("Ancient Den", 4));
|
deckList.add(new CardNameAmount("Ancient Den", 4));
|
||||||
|
deckList.add(new CardNameAmount("Mountain", 56));
|
||||||
|
validationSuccessful = testDeckValid(validator, deckList);
|
||||||
|
Assert.assertFalse(validator.getInvalid().toString(), validationSuccessful);
|
||||||
|
validator.getInvalid().clear();
|
||||||
|
|
||||||
deckList.add(new CardNameAmount("Birthing Pod", 4));
|
deckList.add(new CardNameAmount("Birthing Pod", 4));
|
||||||
|
deckList.add(new CardNameAmount("Mountain", 56));
|
||||||
|
validationSuccessful = testDeckValid(validator, deckList);
|
||||||
|
Assert.assertFalse(validator.getInvalid().toString(), validationSuccessful);
|
||||||
|
validator.getInvalid().clear();
|
||||||
|
|
||||||
|
deckList.clear();
|
||||||
deckList.add(new CardNameAmount("Blazing Shoal", 4));
|
deckList.add(new CardNameAmount("Blazing Shoal", 4));
|
||||||
|
deckList.add(new CardNameAmount("Mountain", 56));
|
||||||
|
validationSuccessful = testDeckValid(validator, deckList);
|
||||||
|
Assert.assertFalse(validator.getInvalid().toString(), validationSuccessful);
|
||||||
|
validator.getInvalid().clear();
|
||||||
|
|
||||||
|
deckList.clear();
|
||||||
deckList.add(new CardNameAmount("Bloodbraid Elf", 4));
|
deckList.add(new CardNameAmount("Bloodbraid Elf", 4));
|
||||||
|
deckList.add(new CardNameAmount("Mountain", 56));
|
||||||
|
validationSuccessful = testDeckValid(validator, deckList);
|
||||||
|
Assert.assertTrue(validator.getInvalid().toString(), validationSuccessful);
|
||||||
|
validator.getInvalid().clear();
|
||||||
|
|
||||||
|
deckList.clear();
|
||||||
deckList.add(new CardNameAmount("Chrome Mox", 4));
|
deckList.add(new CardNameAmount("Chrome Mox", 4));
|
||||||
|
deckList.add(new CardNameAmount("Mountain", 56));
|
||||||
|
validationSuccessful = testDeckValid(validator, deckList);
|
||||||
|
Assert.assertFalse(validator.getInvalid().toString(), validationSuccessful);
|
||||||
|
validator.getInvalid().clear();
|
||||||
|
|
||||||
|
deckList.clear();
|
||||||
deckList.add(new CardNameAmount("Cloudpost", 4));
|
deckList.add(new CardNameAmount("Cloudpost", 4));
|
||||||
|
deckList.add(new CardNameAmount("Mountain", 56));
|
||||||
|
validationSuccessful = testDeckValid(validator, deckList);
|
||||||
|
Assert.assertFalse(validator.getInvalid().toString(), validationSuccessful);
|
||||||
|
validator.getInvalid().clear();
|
||||||
|
|
||||||
|
deckList.clear();
|
||||||
deckList.add(new CardNameAmount("Dark Depths", 4));
|
deckList.add(new CardNameAmount("Dark Depths", 4));
|
||||||
|
deckList.add(new CardNameAmount("Mountain", 56));
|
||||||
|
validationSuccessful = testDeckValid(validator, deckList);
|
||||||
|
Assert.assertFalse(validator.getInvalid().toString(), validationSuccessful);
|
||||||
|
validator.getInvalid().clear();
|
||||||
|
|
||||||
|
deckList.clear();
|
||||||
deckList.add(new CardNameAmount("Deathrite Shaman", 4));
|
deckList.add(new CardNameAmount("Deathrite Shaman", 4));
|
||||||
|
deckList.add(new CardNameAmount("Mountain", 56));
|
||||||
|
validationSuccessful = testDeckValid(validator, deckList);
|
||||||
|
Assert.assertFalse(validator.getInvalid().toString(), validationSuccessful);
|
||||||
|
validator.getInvalid().clear();
|
||||||
|
|
||||||
|
deckList.clear();
|
||||||
deckList.add(new CardNameAmount("Dig Through Time", 4));
|
deckList.add(new CardNameAmount("Dig Through Time", 4));
|
||||||
|
deckList.add(new CardNameAmount("Mountain", 56));
|
||||||
|
validationSuccessful = testDeckValid(validator, deckList);
|
||||||
|
Assert.assertFalse(validator.getInvalid().toString(), validationSuccessful);
|
||||||
|
validator.getInvalid().clear();
|
||||||
|
|
||||||
|
deckList.clear();
|
||||||
deckList.add(new CardNameAmount("Dread Return", 4));
|
deckList.add(new CardNameAmount("Dread Return", 4));
|
||||||
|
deckList.add(new CardNameAmount("Mountain", 56));
|
||||||
|
validationSuccessful = testDeckValid(validator, deckList);
|
||||||
|
Assert.assertFalse(validator.getInvalid().toString(), validationSuccessful);
|
||||||
|
validator.getInvalid().clear();
|
||||||
|
|
||||||
|
deckList.clear();
|
||||||
deckList.add(new CardNameAmount("Glimpse of Nature", 4));
|
deckList.add(new CardNameAmount("Glimpse of Nature", 4));
|
||||||
|
deckList.add(new CardNameAmount("Mountain", 56));
|
||||||
|
validationSuccessful = testDeckValid(validator, deckList);
|
||||||
|
Assert.assertFalse(validator.getInvalid().toString(), validationSuccessful);
|
||||||
|
validator.getInvalid().clear();
|
||||||
|
|
||||||
|
deckList.clear();
|
||||||
deckList.add(new CardNameAmount("Great Furnace", 4));
|
deckList.add(new CardNameAmount("Great Furnace", 4));
|
||||||
|
deckList.add(new CardNameAmount("Mountain", 56));
|
||||||
|
validationSuccessful = testDeckValid(validator, deckList);
|
||||||
|
Assert.assertFalse(validator.getInvalid().toString(), validationSuccessful);
|
||||||
|
validator.getInvalid().clear();
|
||||||
|
|
||||||
|
deckList.clear();
|
||||||
deckList.add(new CardNameAmount("Green Sun's Zenith", 4));
|
deckList.add(new CardNameAmount("Green Sun's Zenith", 4));
|
||||||
|
deckList.add(new CardNameAmount("Mountain", 56));
|
||||||
|
validationSuccessful = testDeckValid(validator, deckList);
|
||||||
|
Assert.assertFalse(validator.getInvalid().toString(), validationSuccessful);
|
||||||
|
validator.getInvalid().clear();
|
||||||
|
|
||||||
|
deckList.clear();
|
||||||
deckList.add(new CardNameAmount("Hypergenesis", 4));
|
deckList.add(new CardNameAmount("Hypergenesis", 4));
|
||||||
|
deckList.add(new CardNameAmount("Mountain", 56));
|
||||||
|
validationSuccessful = testDeckValid(validator, deckList);
|
||||||
|
Assert.assertFalse(validator.getInvalid().toString(), validationSuccessful);
|
||||||
|
validator.getInvalid().clear();
|
||||||
|
|
||||||
|
deckList.clear();
|
||||||
deckList.add(new CardNameAmount("Jace, the Mind Sculptor", 4));
|
deckList.add(new CardNameAmount("Jace, the Mind Sculptor", 4));
|
||||||
|
deckList.add(new CardNameAmount("Mountain", 56));
|
||||||
|
validationSuccessful = testDeckValid(validator, deckList);
|
||||||
|
Assert.assertTrue(validator.getInvalid().toString(), validationSuccessful);
|
||||||
|
validator.getInvalid().clear();
|
||||||
|
|
||||||
|
deckList.clear();
|
||||||
deckList.add(new CardNameAmount("Mental Misstep", 4));
|
deckList.add(new CardNameAmount("Mental Misstep", 4));
|
||||||
Assert.assertFalse("banned cards are not allowed", testDeckValid(new Modern(), deckList));
|
deckList.add(new CardNameAmount("Mountain", 56));
|
||||||
|
validationSuccessful = testDeckValid(validator, deckList);
|
||||||
|
Assert.assertFalse(validator.getInvalid().toString(), validationSuccessful);
|
||||||
|
validator.getInvalid().clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean testDeckValid(DeckValidator validator, List<CardNameAmount> cards) {
|
private boolean testDeckValid(DeckValidator validator, List<CardNameAmount> cards) {
|
||||||
|
return testDeckValid(validator, cards, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean testDeckValid(DeckValidator validator, List<CardNameAmount> cards, List<CardNameAmount> cardsSideboard) {
|
||||||
Deck deckToTest = new Deck();
|
Deck deckToTest = new Deck();
|
||||||
for (CardNameAmount cardNameAmount : cards) {
|
if (cards != null) {
|
||||||
CardInfo cardinfo;
|
for (CardNameAmount cardNameAmount : cards) {
|
||||||
if (cardNameAmount.getName().isEmpty()) {
|
CardInfo cardinfo;
|
||||||
cardinfo = CardRepository.instance.findCard(cardNameAmount.getSetCode(), cardNameAmount.getCardNumber());
|
if (cardNameAmount.getName().isEmpty()) {
|
||||||
} else {
|
cardinfo = CardRepository.instance.findCard(cardNameAmount.getSetCode(), cardNameAmount.getCardNumber());
|
||||||
cardinfo = CardRepository.instance.findCard(cardNameAmount.getName());
|
} else {
|
||||||
|
cardinfo = CardRepository.instance.findCard(cardNameAmount.getName());
|
||||||
|
}
|
||||||
|
for (int i = 0; i < cardNameAmount.getNumber(); i++) {
|
||||||
|
deckToTest.getCards().add(cardinfo.getCard());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (int i = 0; i < cardNameAmount.getNumber(); i++) {
|
}
|
||||||
deckToTest.getCards().add(cardinfo.getCard());
|
if (cardsSideboard != null) {
|
||||||
|
for (CardNameAmount cardNameAmount : cardsSideboard) {
|
||||||
|
CardInfo cardinfo;
|
||||||
|
if (cardNameAmount.getName().isEmpty()) {
|
||||||
|
cardinfo = CardRepository.instance.findCard(cardNameAmount.getSetCode(), cardNameAmount.getCardNumber());
|
||||||
|
} else {
|
||||||
|
cardinfo = CardRepository.instance.findCard(cardNameAmount.getName());
|
||||||
|
}
|
||||||
|
for (int i = 0; i < cardNameAmount.getNumber(); i++) {
|
||||||
|
deckToTest.getSideboard().add(cardinfo.getCard());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return validator.validate(deckToTest);
|
return validator.validate(deckToTest);
|
||||||
|
|
|
@ -44,7 +44,6 @@ import mage.abilities.effects.Effects;
|
||||||
import mage.abilities.effects.OneShotEffect;
|
import mage.abilities.effects.OneShotEffect;
|
||||||
import mage.abilities.effects.common.DynamicManaEffect;
|
import mage.abilities.effects.common.DynamicManaEffect;
|
||||||
import mage.abilities.effects.common.ManaEffect;
|
import mage.abilities.effects.common.ManaEffect;
|
||||||
import mage.abilities.keyword.FlashbackAbility;
|
|
||||||
import mage.abilities.mana.ActivatedManaAbilityImpl;
|
import mage.abilities.mana.ActivatedManaAbilityImpl;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
import mage.cards.SplitCard;
|
import mage.cards.SplitCard;
|
||||||
|
@ -337,9 +336,7 @@ public abstract class AbilityImpl implements Ability {
|
||||||
if (sourceObject != null && this.getAbilityType() != AbilityType.TRIGGERED) { // triggered abilities check this already in playerImpl.triggerAbility
|
if (sourceObject != null && this.getAbilityType() != AbilityType.TRIGGERED) { // triggered abilities check this already in playerImpl.triggerAbility
|
||||||
sourceObject.adjustTargets(this, game);
|
sourceObject.adjustTargets(this, game);
|
||||||
}
|
}
|
||||||
// Flashback abilities haven't made the choices the underlying spell might need for targeting.
|
if (!getTargets().isEmpty()) {
|
||||||
if (!(this instanceof FlashbackAbility)
|
|
||||||
&& !getTargets().isEmpty()) {
|
|
||||||
Outcome outcome = getEffects().isEmpty() ? Outcome.Detriment : getEffects().get(0).getOutcome();
|
Outcome outcome = getEffects().isEmpty() ? Outcome.Detriment : getEffects().get(0).getOutcome();
|
||||||
if (getTargets().chooseTargets(outcome, this.controllerId, this, noMana, game) == false) {
|
if (getTargets().chooseTargets(outcome, this.controllerId, this, noMana, game) == false) {
|
||||||
if ((variableManaCost != null || announceString != null)) {
|
if ((variableManaCost != null || announceString != null)) {
|
||||||
|
@ -445,8 +442,15 @@ public abstract class AbilityImpl implements Ability {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean activateAlternateOrAdditionalCosts(MageObject sourceObject, boolean noMana, Player controller, Game game) {
|
public boolean activateAlternateOrAdditionalCosts(MageObject sourceObject, boolean noMana, Player controller, Game game) {
|
||||||
|
if (this instanceof SpellAbility) {
|
||||||
|
if (((SpellAbility) this).getSpellAbilityCastMode() != SpellAbilityCastMode.NORMAL) {
|
||||||
|
// A player can't apply two alternative methods of casting or two alternative costs to a single spell.
|
||||||
|
// So can only use alternate costs if the spell is cast in normal mode
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
boolean alternativeCostisUsed = false;
|
boolean alternativeCostisUsed = false;
|
||||||
if (sourceObject != null && !(sourceObject instanceof Permanent) && !(this instanceof FlashbackAbility)) {
|
if (sourceObject != null && !(sourceObject instanceof Permanent)) {
|
||||||
Abilities<Ability> abilities = null;
|
Abilities<Ability> abilities = null;
|
||||||
if (sourceObject instanceof Card) {
|
if (sourceObject instanceof Card) {
|
||||||
abilities = ((Card) sourceObject).getAbilities(game);
|
abilities = ((Card) sourceObject).getAbilities(game);
|
||||||
|
|
|
@ -217,7 +217,7 @@ public class SpellAbility extends ActivatedAbilityImpl {
|
||||||
this.name = "Cast fused " + cardName;
|
this.name = "Cast fused " + cardName;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
this.name = "Cast " + cardName + (this.spellAbilityCastMode != SpellAbilityCastMode.NORMAL ? " by " + spellAbilityCastMode.toString() : "");
|
this.name = "Cast " + cardName + (this.spellAbilityCastMode != SpellAbilityCastMode.NORMAL ? " using " + spellAbilityCastMode.toString() : "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,4 +230,11 @@ public class SpellAbility extends ActivatedAbilityImpl {
|
||||||
setSpellName();
|
setSpellName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SpellAbility getSpellAbilityToResolve(Game game) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(UUID idToUse) {
|
||||||
|
this.id = idToUse;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,6 @@ package mage.abilities.costs;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.keyword.FlashbackAbility;
|
|
||||||
import mage.abilities.mana.ManaAbility;
|
import mage.abilities.mana.ManaAbility;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.stack.StackObject;
|
import mage.game.stack.StackObject;
|
||||||
|
@ -173,7 +172,6 @@ public abstract class VariableCostImpl implements Cost, VariableCost {
|
||||||
StackObject stackObject = game.getStack().getStackObject(source.getId());
|
StackObject stackObject = game.getStack().getStackObject(source.getId());
|
||||||
if (controller != null
|
if (controller != null
|
||||||
&& (source instanceof ManaAbility
|
&& (source instanceof ManaAbility
|
||||||
|| source instanceof FlashbackAbility
|
|
||||||
|| stackObject != null)) {
|
|| stackObject != null)) {
|
||||||
xValue = controller.announceXCost(getMinValue(source, game), getMaxValue(source, game),
|
xValue = controller.announceXCost(getMinValue(source, game), getMaxValue(source, game),
|
||||||
"Announce the number of " + actionText, game, source, this);
|
"Announce the number of " + actionText, game, source, this);
|
||||||
|
|
|
@ -55,19 +55,19 @@ public class SacrificeAllCost extends CostImpl {
|
||||||
|
|
||||||
public SacrificeAllCost(final SacrificeAllCost cost) {
|
public SacrificeAllCost(final SacrificeAllCost cost) {
|
||||||
super(cost);
|
super(cost);
|
||||||
for (Permanent permanent: cost.permanents) {
|
this.permanents.addAll(cost.permanents); // because this are already copied permanents, they can't change, so no copy again is needed
|
||||||
this.permanents.add(permanent.copy());
|
|
||||||
}
|
|
||||||
this.filter = cost.filter.copy();
|
this.filter = cost.filter.copy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) {
|
public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) {
|
||||||
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, controllerId, game)) {
|
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, controllerId, game)) {
|
||||||
permanents.add(permanent.copy());
|
if (permanent.sacrifice(sourceId, game)) {
|
||||||
permanent.sacrifice(sourceId, game);
|
permanents.add(permanent.copy());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
paid = true;
|
||||||
|
return paid;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -82,10 +82,10 @@ public class SacrificeAllCost extends CostImpl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Permanent permanent :game.getBattlefield().getAllActivePermanents(filter, controllerId, game)) {
|
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, controllerId, game)) {
|
||||||
if(!game.getPlayer(activator).canPaySacrificeCost(permanent, sourceId, controllerId, game)) {
|
if (!game.getPlayer(activator).canPaySacrificeCost(permanent, sourceId, controllerId, game)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -142,42 +142,50 @@ public class MaximumHandSizeControllerEffect extends ContinuousEffectImpl {
|
||||||
|
|
||||||
private void setText() {
|
private void setText() {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
switch (targetController) {
|
if(handSize instanceof StaticValue && ((StaticValue) handSize).getValue() == Integer.MAX_VALUE) {
|
||||||
case ANY:
|
switch (targetController) {
|
||||||
if (handSize instanceof StaticValue && ((StaticValue) handSize).getValue() == Integer.MAX_VALUE) {
|
case ANY:
|
||||||
sb.append("All players have no ");
|
sb.append("Players have no maximum hand size");
|
||||||
} else {
|
break;
|
||||||
sb.append("All players ");
|
case OPPONENT:
|
||||||
}
|
sb.append("Each opponent has no maximum hand size");
|
||||||
break;
|
break;
|
||||||
case OPPONENT:
|
case YOU:
|
||||||
if (handSize instanceof StaticValue && ((StaticValue) handSize).getValue() == Integer.MAX_VALUE) {
|
sb.append("You have no maximum hand size");
|
||||||
sb.append("Each opponent has no ");
|
break;
|
||||||
} else {
|
}
|
||||||
sb.append("Each opponent's ");
|
} else {
|
||||||
}
|
switch (targetController) {
|
||||||
break;
|
case ANY:
|
||||||
case YOU:
|
sb.append("All players maximum hand size");
|
||||||
if (handSize instanceof StaticValue && ((StaticValue) handSize).getValue() == Integer.MAX_VALUE) {
|
break;
|
||||||
sb.append("You have no ");
|
case OPPONENT:
|
||||||
} else {
|
sb.append("Each opponent's maximum hand size");
|
||||||
sb.append("Your ");
|
break;
|
||||||
}
|
case YOU:
|
||||||
break;
|
sb.append("Your maximum hand size");
|
||||||
}
|
break;
|
||||||
sb.append("maximum hand size");
|
}
|
||||||
if (handSizeModification == HandSizeModification.INCREASE) {
|
|
||||||
sb.append(" is increased by ");
|
switch (handSizeModification) {
|
||||||
} else if (handSizeModification == HandSizeModification.REDUCE) {
|
case SET:
|
||||||
sb.append(" is reduced by ");
|
sb.append(" is ");
|
||||||
} else if (!((handSize instanceof StaticValue) && ((StaticValue) handSize).getValue() != Integer.MAX_VALUE) || !(handSize instanceof StaticValue)) {
|
break;
|
||||||
sb.append(" is ");
|
case INCREASE:
|
||||||
}
|
sb.append(" is increased by ");
|
||||||
if ((handSize instanceof StaticValue && ((StaticValue) handSize).getValue() != Integer.MAX_VALUE)) {
|
break;
|
||||||
sb.append(CardUtil.numberToText(((StaticValue) handSize).getValue()));
|
case REDUCE:
|
||||||
} else if (!(handSize instanceof StaticValue)) {
|
sb.append(" is reduced by ");
|
||||||
sb.append(handSize.getMessage());
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handSize instanceof StaticValue) {
|
||||||
|
sb.append(CardUtil.numberToText(((StaticValue) handSize).getValue()));
|
||||||
|
} else if (!(handSize instanceof StaticValue)) {
|
||||||
|
sb.append(handSize.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (duration == Duration.EndOfGame) {
|
if (duration == Duration.EndOfGame) {
|
||||||
sb.append(" for the rest of the game");
|
sb.append(" for the rest of the game");
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ public class SpellsCostReductionAllEffect extends CostModificationEffectImpl {
|
||||||
private final boolean upTo;
|
private final boolean upTo;
|
||||||
|
|
||||||
public SpellsCostReductionAllEffect(int amount) {
|
public SpellsCostReductionAllEffect(int amount) {
|
||||||
this(new FilterCard("All Spells "), amount);
|
this(new FilterCard("Spells"), amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SpellsCostReductionAllEffect(FilterCard filter, int amount) {
|
public SpellsCostReductionAllEffect(FilterCard filter, int amount) {
|
||||||
|
|
|
@ -187,6 +187,7 @@ class EchoEffect extends OneShotEffect {
|
||||||
if (controller.chooseUse(Outcome.Benefit, "Pay " + cost.getText() + '?', source, game)) {
|
if (controller.chooseUse(Outcome.Benefit, "Pay " + cost.getText() + '?', source, game)) {
|
||||||
cost.clearPaid();
|
cost.clearPaid();
|
||||||
if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) {
|
if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) {
|
||||||
|
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.ECHO_PAID, source.getSourceId(), source.getSourceId(), source.getControllerId()));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,14 +32,13 @@ import mage.abilities.Ability;
|
||||||
import mage.abilities.SpellAbility;
|
import mage.abilities.SpellAbility;
|
||||||
import mage.abilities.costs.Cost;
|
import mage.abilities.costs.Cost;
|
||||||
import mage.abilities.costs.Costs;
|
import mage.abilities.costs.Costs;
|
||||||
import mage.abilities.costs.mana.ManaCost;
|
|
||||||
import mage.abilities.effects.ContinuousEffect;
|
import mage.abilities.effects.ContinuousEffect;
|
||||||
import mage.abilities.effects.OneShotEffect;
|
|
||||||
import mage.abilities.effects.ReplacementEffectImpl;
|
import mage.abilities.effects.ReplacementEffectImpl;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
import mage.cards.SplitCard;
|
import mage.cards.SplitCard;
|
||||||
import mage.constants.Duration;
|
import mage.constants.Duration;
|
||||||
import mage.constants.Outcome;
|
import mage.constants.Outcome;
|
||||||
|
import mage.constants.SpellAbilityCastMode;
|
||||||
import mage.constants.SpellAbilityType;
|
import mage.constants.SpellAbilityType;
|
||||||
import mage.constants.TimingRule;
|
import mage.constants.TimingRule;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
|
@ -66,23 +65,21 @@ import mage.target.targetpointer.FixedTarget;
|
||||||
public class FlashbackAbility extends SpellAbility {
|
public class FlashbackAbility extends SpellAbility {
|
||||||
|
|
||||||
private String abilityName;
|
private String abilityName;
|
||||||
|
private SpellAbility spellAbilityToResolve;
|
||||||
|
|
||||||
public FlashbackAbility(Cost cost, TimingRule timingRule) {
|
public FlashbackAbility(Cost cost, TimingRule timingRule) {
|
||||||
super(null, "", Zone.GRAVEYARD);
|
super(null, "", Zone.GRAVEYARD, SpellAbilityType.BASE_ALTERNATE, SpellAbilityCastMode.FLASHBACK);
|
||||||
this.setAdditionalCostsRuleVisible(false);
|
this.setAdditionalCostsRuleVisible(false);
|
||||||
this.name = "Flashback " + cost.getText();
|
this.name = "Flashback " + cost.getText();
|
||||||
this.addEffect(new FlashbackEffect());
|
|
||||||
this.addCost(cost);
|
this.addCost(cost);
|
||||||
this.timing = timingRule;
|
this.timing = timingRule;
|
||||||
this.usesStack = false;
|
|
||||||
this.spellAbilityType = SpellAbilityType.BASE_ALTERNATE;
|
|
||||||
setCostModificationActive(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public FlashbackAbility(final FlashbackAbility ability) {
|
public FlashbackAbility(final FlashbackAbility ability) {
|
||||||
super(ability);
|
super(ability);
|
||||||
this.spellAbilityType = ability.spellAbilityType;
|
this.spellAbilityType = ability.spellAbilityType;
|
||||||
this.abilityName = ability.abilityName;
|
this.abilityName = ability.abilityName;
|
||||||
|
this.spellAbilityToResolve = ability.spellAbilityToResolve;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -108,6 +105,47 @@ public class FlashbackAbility extends SpellAbility {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SpellAbility getSpellAbilityToResolve(Game game) {
|
||||||
|
Card card = game.getCard(getSourceId());
|
||||||
|
if (card != null) {
|
||||||
|
if (spellAbilityToResolve == null) {
|
||||||
|
SpellAbility spellAbilityCopy = null;
|
||||||
|
if (card.isSplitCard()) {
|
||||||
|
if (((SplitCard) card).getLeftHalfCard().getName().equals(abilityName)) {
|
||||||
|
spellAbilityCopy = ((SplitCard) card).getLeftHalfCard().getSpellAbility().copy();
|
||||||
|
} else if (((SplitCard) card).getRightHalfCard().getName().equals(abilityName)) {
|
||||||
|
spellAbilityCopy = ((SplitCard) card).getRightHalfCard().getSpellAbility().copy();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
spellAbilityCopy = card.getSpellAbility().copy();
|
||||||
|
}
|
||||||
|
if (spellAbilityCopy == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
spellAbilityCopy.setId(this.getId());
|
||||||
|
spellAbilityCopy.getManaCosts().clear();
|
||||||
|
spellAbilityCopy.getManaCostsToPay().clear();
|
||||||
|
spellAbilityCopy.getCosts().addAll(this.getCosts());
|
||||||
|
spellAbilityCopy.addCost(this.getManaCosts());
|
||||||
|
spellAbilityCopy.setSpellAbilityCastMode(this.getSpellAbilityCastMode());
|
||||||
|
spellAbilityToResolve = spellAbilityCopy;
|
||||||
|
ContinuousEffect effect = new FlashbackReplacementEffect();
|
||||||
|
effect.setTargetPointer(new FixedTarget(getSourceId(), game.getState().getZoneChangeCounter(getSourceId())));
|
||||||
|
game.addEffect(effect, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return spellAbilityToResolve;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Costs<Cost> getCosts() {
|
||||||
|
if (spellAbilityToResolve == null) {
|
||||||
|
return super.getCosts();
|
||||||
|
}
|
||||||
|
return spellAbilityToResolve.getCosts();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FlashbackAbility copy() {
|
public FlashbackAbility copy() {
|
||||||
return new FlashbackAbility(this);
|
return new FlashbackAbility(this);
|
||||||
|
@ -144,102 +182,18 @@ public class FlashbackAbility extends SpellAbility {
|
||||||
return sbRule.toString();
|
return sbRule.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public void setSpellAbilityType(SpellAbilityType spellAbilityType) {
|
* Used for split card sin PlayerImpl method:
|
||||||
this.spellAbilityType = spellAbilityType;
|
* getOtherUseableActivatedAbilities
|
||||||
}
|
*
|
||||||
|
* @param abilityName
|
||||||
@Override
|
*/
|
||||||
public SpellAbilityType getSpellAbilityType() {
|
|
||||||
return this.spellAbilityType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAbilityName(String abilityName) {
|
public void setAbilityName(String abilityName) {
|
||||||
this.abilityName = abilityName;
|
this.abilityName = abilityName;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class FlashbackEffect extends OneShotEffect {
|
|
||||||
|
|
||||||
public FlashbackEffect() {
|
|
||||||
super(Outcome.Benefit);
|
|
||||||
staticText = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
public FlashbackEffect(final FlashbackEffect effect) {
|
|
||||||
super(effect);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public FlashbackEffect copy() {
|
|
||||||
return new FlashbackEffect(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean apply(Game game, Ability source) {
|
|
||||||
Card card = (Card) game.getObject(source.getSourceId());
|
|
||||||
if (card != null) {
|
|
||||||
Player controller = game.getPlayer(source.getControllerId());
|
|
||||||
if (controller != null) {
|
|
||||||
SpellAbility spellAbility;
|
|
||||||
switch (((FlashbackAbility) source).getSpellAbilityType()) {
|
|
||||||
case SPLIT_LEFT:
|
|
||||||
spellAbility = ((SplitCard) card).getLeftHalfCard().getSpellAbility().copy();
|
|
||||||
break;
|
|
||||||
case SPLIT_RIGHT:
|
|
||||||
spellAbility = ((SplitCard) card).getRightHalfCard().getSpellAbility().copy();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
spellAbility = card.getSpellAbility().copy();
|
|
||||||
}
|
|
||||||
|
|
||||||
spellAbility.clear();
|
|
||||||
// set the payed flashback costs to the spell ability so abilities like Converge or calculation of {X} values work
|
|
||||||
spellAbility.getManaCostsToPay().clear();
|
|
||||||
spellAbility.getManaCostsToPay().addAll(source.getManaCosts());
|
|
||||||
spellAbility.getManaCosts().clear();
|
|
||||||
spellAbility.getManaCosts().addAll(source.getManaCosts());
|
|
||||||
// needed to get e.g. paid costs from Conflagrate
|
|
||||||
|
|
||||||
for (Cost cost : source.getCosts()) {
|
|
||||||
if (cost instanceof Costs) {
|
|
||||||
Costs<Cost> listOfCosts = (Costs<Cost>) cost;
|
|
||||||
for (Cost singleCost : listOfCosts) {
|
|
||||||
if (singleCost instanceof ManaCost) {
|
|
||||||
singleCost.clearPaid();
|
|
||||||
spellAbility.getManaCosts().add((ManaCost) singleCost);
|
|
||||||
spellAbility.getManaCostsToPay().add((ManaCost) singleCost);
|
|
||||||
} else {
|
|
||||||
spellAbility.getCosts().add(singleCost);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if (cost instanceof ManaCost) {
|
|
||||||
spellAbility.getManaCosts().add((ManaCost) cost);
|
|
||||||
spellAbility.getManaCostsToPay().add((ManaCost) cost);
|
|
||||||
} else {
|
|
||||||
spellAbility.getCosts().add(cost);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!game.isSimulation()) {
|
|
||||||
game.informPlayers(controller.getLogName() + " flashbacks " + card.getLogName());
|
|
||||||
}
|
|
||||||
if (controller.cast(spellAbility, game, false)) {
|
|
||||||
ContinuousEffect effect = new FlashbackReplacementEffect();
|
|
||||||
effect.setTargetPointer(new FixedTarget(source.getSourceId(), game.getState().getZoneChangeCounter(source.getSourceId())));
|
|
||||||
game.addEffect(effect, source);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class FlashbackReplacementEffect extends ReplacementEffectImpl {
|
class FlashbackReplacementEffect extends ReplacementEffectImpl {
|
||||||
|
|
||||||
public FlashbackReplacementEffect() {
|
public FlashbackReplacementEffect() {
|
||||||
|
@ -287,7 +241,7 @@ class FlashbackReplacementEffect extends ReplacementEffectImpl {
|
||||||
&& ((ZoneChangeEvent) event).getToZone() != Zone.EXILED) {
|
&& ((ZoneChangeEvent) event).getToZone() != Zone.EXILED) {
|
||||||
|
|
||||||
int zcc = game.getState().getZoneChangeCounter(source.getSourceId());
|
int zcc = game.getState().getZoneChangeCounter(source.getSourceId());
|
||||||
if (((FixedTarget) getTargetPointer()).getZoneChangeCounter() == zcc) {
|
if (((FixedTarget) getTargetPointer()).getZoneChangeCounter() + 1 == zcc) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -516,7 +516,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
||||||
Card mainCard = getMainCard();
|
Card mainCard = getMainCard();
|
||||||
ZoneChangeEvent event = new ZoneChangeEvent(mainCard.getId(), ability.getId(), controllerId, fromZone, Zone.STACK);
|
ZoneChangeEvent event = new ZoneChangeEvent(mainCard.getId(), ability.getId(), controllerId, fromZone, Zone.STACK);
|
||||||
ZoneChangeInfo.Stack info
|
ZoneChangeInfo.Stack info
|
||||||
= new ZoneChangeInfo.Stack(event, new Spell(this, ability.copy(), controllerId, event.getFromZone()));
|
= new ZoneChangeInfo.Stack(event, new Spell(this, ability.getSpellAbilityToResolve(game), controllerId, event.getFromZone()));
|
||||||
return ZonesHandler.cast(info, game);
|
return ZonesHandler.cast(info, game);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,8 @@ package mage.constants;
|
||||||
*/
|
*/
|
||||||
public enum SpellAbilityCastMode {
|
public enum SpellAbilityCastMode {
|
||||||
NORMAL("Normal"),
|
NORMAL("Normal"),
|
||||||
MADNESS("Madness");
|
MADNESS("Madness"),
|
||||||
|
FLASHBACK("Flashback");
|
||||||
|
|
||||||
private final String text;
|
private final String text;
|
||||||
|
|
||||||
|
|
|
@ -732,42 +732,35 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
|
||||||
|
|
||||||
for (UUID uuid : attackers) {
|
for (UUID uuid : attackers) {
|
||||||
Permanent attacker = game.getPermanent(uuid);
|
Permanent attacker = game.getPermanent(uuid);
|
||||||
// Check if there are enough blockers to have a legal block
|
if (attacker != null && this.blocked) {
|
||||||
if (attacker != null && this.blocked && attacker.getMinBlockedBy() > 1 && !blockers.isEmpty() && blockers.size() < attacker.getMinBlockedBy()) {
|
// Check if there are enough blockers to have a legal block
|
||||||
for (UUID blockerId : blockers) {
|
if (attacker.getMinBlockedBy() > 1 && !blockers.isEmpty() && blockers.size() < attacker.getMinBlockedBy()) {
|
||||||
Permanent blocker = game.getPermanent(blockerId);
|
for (UUID blockerId : new ArrayList<>(blockers)) {
|
||||||
if (blocker != null) {
|
game.getCombat().removeBlocker(blockerId, game);
|
||||||
blocker.setBlocking(blocker.getBlocking() - 1);
|
|
||||||
}
|
}
|
||||||
}
|
blockers.clear();
|
||||||
blockers.clear();
|
blockerOrder.clear();
|
||||||
blockerOrder.clear();
|
if (!game.isSimulation()) {
|
||||||
this.blocked = false;
|
game.informPlayers(attacker.getLogName() + " can't be blocked except by " + attacker.getMinBlockedBy() + " or more creatures. Blockers discarded.");
|
||||||
if (!game.isSimulation()) {
|
|
||||||
game.informPlayers(attacker.getLogName() + " can't be blocked except by " + attacker.getMinBlockedBy() + " or more creatures. Blockers discarded.");
|
|
||||||
}
|
|
||||||
blockWasLegal = false;
|
|
||||||
}
|
|
||||||
// Check if there are too many blockers (maxBlockedBy = 0 means no restrictions)
|
|
||||||
if (attacker != null && this.blocked && attacker.getMaxBlockedBy() > 0 && attacker.getMaxBlockedBy() < blockers.size()) {
|
|
||||||
for (UUID blockerId : blockers) {
|
|
||||||
Permanent blocker = game.getPermanent(blockerId);
|
|
||||||
if (blocker != null) {
|
|
||||||
blocker.setBlocking(blocker.getBlocking() - 1);
|
|
||||||
}
|
}
|
||||||
|
blockWasLegal = false;
|
||||||
}
|
}
|
||||||
blockers.clear();
|
// Check if there are too many blockers (maxBlockedBy = 0 means no restrictions)
|
||||||
blockerOrder.clear();
|
if (attacker.getMaxBlockedBy() > 0 && attacker.getMaxBlockedBy() < blockers.size()) {
|
||||||
this.blocked = false;
|
for (UUID blockerId : new ArrayList<>(blockers)) {
|
||||||
if (!game.isSimulation()) {
|
game.getCombat().removeBlocker(blockerId, game);
|
||||||
game.informPlayers(new StringBuilder(attacker.getLogName())
|
}
|
||||||
.append(" can't be blocked by more than ").append(attacker.getMaxBlockedBy())
|
blockers.clear();
|
||||||
.append(attacker.getMaxBlockedBy() == 1 ? " creature." : " creatures.")
|
blockerOrder.clear();
|
||||||
.append(" Blockers discarded.").toString());
|
if (!game.isSimulation()) {
|
||||||
|
game.informPlayers(new StringBuilder(attacker.getLogName())
|
||||||
|
.append(" can't be blocked by more than ").append(attacker.getMaxBlockedBy())
|
||||||
|
.append(attacker.getMaxBlockedBy() == 1 ? " creature." : " creatures.")
|
||||||
|
.append(" Blockers discarded.").toString());
|
||||||
|
}
|
||||||
|
blockWasLegal = false;
|
||||||
}
|
}
|
||||||
blockWasLegal = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return blockWasLegal;
|
return blockWasLegal;
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,6 +92,7 @@ public class GameEvent implements Serializable {
|
||||||
DRAW_CARDS, // applies to an instruction to draw more than one card before any replacement effects apply to individual cards drawn
|
DRAW_CARDS, // applies to an instruction to draw more than one card before any replacement effects apply to individual cards drawn
|
||||||
DRAW_CARD, DREW_CARD,
|
DRAW_CARD, DREW_CARD,
|
||||||
EXPLORED,
|
EXPLORED,
|
||||||
|
ECHO_PAID,
|
||||||
MIRACLE_CARD_REVEALED,
|
MIRACLE_CARD_REVEALED,
|
||||||
MADNESS_CARD_EXILED,
|
MADNESS_CARD_EXILED,
|
||||||
INVESTIGATED,
|
INVESTIGATED,
|
||||||
|
|
|
@ -1158,7 +1158,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int bookmark = game.bookmarkState();
|
int bookmark = game.bookmarkState();
|
||||||
if (ability.activate(game, ability instanceof FlashbackAbility)) {
|
if (ability.activate(game, false)) {
|
||||||
ability.resolve(game);
|
ability.resolve(game);
|
||||||
game.removeBookmark(bookmark);
|
game.removeBookmark(bookmark);
|
||||||
resetStoredBookmark(game);
|
resetStoredBookmark(game);
|
||||||
|
@ -1219,11 +1219,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
result = playManaAbility((ActivatedManaAbilityImpl) ability.copy(), game);
|
result = playManaAbility((ActivatedManaAbilityImpl) ability.copy(), game);
|
||||||
break;
|
break;
|
||||||
case SPELL:
|
case SPELL:
|
||||||
if (ability instanceof FlashbackAbility) {
|
result = cast((SpellAbility) ability.copy(), game, false);
|
||||||
result = playAbility(ability.copy(), game);
|
|
||||||
} else {
|
|
||||||
result = cast((SpellAbility) ability, game, false);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
result = playAbility(ability.copy(), game);
|
result = playAbility(ability.copy(), game);
|
||||||
|
|
|
@ -89,4 +89,9 @@ public class BlockedAttackerWatcher extends Watcher {
|
||||||
Set<MageObjectReference> blockedAttackers = blockData.get(new MageObjectReference(blocker, game));
|
Set<MageObjectReference> blockedAttackers = blockData.get(new MageObjectReference(blocker, game));
|
||||||
return blockedAttackers != null && blockedAttackers.contains(new MageObjectReference(attacker, game));
|
return blockedAttackers != null && blockedAttackers.contains(new MageObjectReference(attacker, game));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean creatureHasBlockedAttacker(MageObjectReference attacker, MageObjectReference blocker, Game game) {
|
||||||
|
Set<MageObjectReference> blockedAttackers = blockData.get(blocker);
|
||||||
|
return blockedAttackers != null && blockedAttackers.contains(attacker);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue