Merge remote-tracking branch 'remotes/upstream/master'

This commit is contained in:
ciaccona007 2017-07-16 13:10:43 -04:00
commit 95d0fe8802
45 changed files with 702 additions and 338 deletions

View file

@ -5,8 +5,12 @@ import java.awt.image.BufferedImage;
import java.io.*; import java.io.*;
import java.net.*; import java.net.*;
import java.nio.file.AccessDeniedException; import java.nio.file.AccessDeniedException;
import java.util.*; import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -103,7 +107,7 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
p0.add(jLabel1); p0.add(jLabel1);
p0.add(Box.createVerticalStrut(5)); p0.add(Box.createVerticalStrut(5));
ComboBoxModel jComboBox1Model = new DefaultComboBoxModel(new String[]{ ComboBoxModel jComboBox1Model = new DefaultComboBoxModel(new String[]{
"magiccards.info", // "magiccards.info",
"wizards.com", "wizards.com",
"mythicspoiler.com", "mythicspoiler.com",
"tokens.mtg.onl", //"mtgimage.com (HQ)", "tokens.mtg.onl", //"mtgimage.com (HQ)",
@ -111,8 +115,7 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
"alternative.mtg.onl", "alternative.mtg.onl",
"GrabBag", "GrabBag",
"magidex.com", "magidex.com",
"scryfall.com", "scryfall.com", //"mtgathering.ru HQ",
//"mtgathering.ru HQ",
//"mtgathering.ru MQ", //"mtgathering.ru MQ",
//"mtgathering.ru LQ", //"mtgathering.ru LQ",
}); });

View file

@ -27,10 +27,6 @@
*/ */
package mage.server; package mage.server;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
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;
@ -40,6 +36,11 @@ import mage.view.ChatMessage.MessageType;
import mage.view.ChatMessage.SoundToPlay; import mage.view.ChatMessage.SoundToPlay;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/** /**
* @author BetaSteward_at_googlemail.com * @author BetaSteward_at_googlemail.com
*/ */
@ -290,7 +291,7 @@ public enum ChatManager {
} }
} }
public ArrayList<ChatSession> getChatSessions() { public List<ChatSession> getChatSessions() {
return new ArrayList<>(chatSessions.values()); return new ArrayList<>(chatSessions.values());
} }

View file

@ -36,10 +36,7 @@ import mage.view.ChatMessage.SoundToPlay;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import java.text.DateFormat; import java.text.DateFormat;
import java.util.Date; import java.util.*;
import java.util.HashSet;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
/** /**
@ -119,7 +116,7 @@ public class ChatSession {
public void broadcast(String userName, String message, MessageColor color, boolean withTime, MessageType messageType, SoundToPlay soundToPlay) { public void broadcast(String userName, String message, MessageColor color, boolean withTime, MessageType messageType, SoundToPlay soundToPlay) {
if (!message.isEmpty()) { if (!message.isEmpty()) {
HashSet<UUID> clientsToRemove = new HashSet<>(); Set<UUID> clientsToRemove = new HashSet<>();
ClientCallback clientCallback = new ClientCallback(ClientCallbackMethod.CHATMESSAGE, chatId, new ChatMessage(userName, message, (withTime ? timeFormatter.format(new Date()) : ""), color, messageType, soundToPlay)); ClientCallback clientCallback = new ClientCallback(ClientCallbackMethod.CHATMESSAGE, chatId, new ChatMessage(userName, message, (withTime ? timeFormatter.format(new Date()) : ""), color, messageType, soundToPlay));
for (UUID userId : clients.keySet()) { for (UUID userId : clients.keySet()) {
Optional<User> user = UserManager.instance.getUser(userId); Optional<User> user = UserManager.instance.getUser(userId);

View file

@ -369,7 +369,7 @@ public enum TableManager {
+ " | " + sessionState + " | " + sessionState
+ " | " + user.getName() + " (" + user.getUserState().toString() + " - " + user.getPingInfo() + ')'); + " | " + user.getName() + " (" + user.getUserState().toString() + " - " + user.getPingInfo() + ')');
} }
ArrayList<ChatSession> chatSessions = ChatManager.instance.getChatSessions(); List<ChatSession> chatSessions = ChatManager.instance.getChatSessions();
logger.debug("------- ChatSessions: " + chatSessions.size() + " ----------------------------------"); logger.debug("------- ChatSessions: " + chatSessions.size() + " ----------------------------------");
for (ChatSession chatSession : chatSessions) { for (ChatSession chatSession : chatSessions) {
logger.debug(chatSession.getChatId() + " " + formatter.format(chatSession.getCreateTime()) + ' ' + chatSession.getInfo() + ' ' + chatSession.getClients().values().toString()); logger.debug(chatSession.getChatId() + " " + formatter.format(chatSession.getCreateTime()) + ' ' + chatSession.getInfo() + ' ' + chatSession.getClients().values().toString());
@ -387,7 +387,7 @@ public enum TableManager {
debugServerState(); debugServerState();
} }
logger.debug("TABLE HEALTH CHECK"); logger.debug("TABLE HEALTH CHECK");
ArrayList<Table> tableCopy = new ArrayList<>(tables.values()); List<Table> tableCopy = new ArrayList<>(tables.values());
for (Table table : tableCopy) { for (Table table : tableCopy) {
try { try {
if (table.getState() != TableState.FINISHED) { if (table.getState() != TableState.FINISHED) {

View file

@ -73,7 +73,7 @@ public class User {
private final String host; private final String host;
private final Date connectionTime; private final Date connectionTime;
private final Map<UUID, Table> tables; private final Map<UUID, Table> tables;
private final ArrayList<UUID> tablesToDelete; private final List<UUID> tablesToDelete;
private final Map<UUID, GameSessionPlayer> gameSessions; private final Map<UUID, GameSessionPlayer> gameSessions;
private final Map<UUID, DraftSession> draftSessions; private final Map<UUID, DraftSession> draftSessions;
private final Map<UUID, UUID> userTournaments; // playerId, tournamentId private final Map<UUID, UUID> userTournaments; // playerId, tournamentId

View file

@ -88,8 +88,8 @@ public class GamesRoomImpl extends RoomImpl implements GamesRoom, Serializable {
private void update() { private void update() {
List<Table> allTables = new ArrayList<>(tables.values()); List<Table> allTables = new ArrayList<>(tables.values());
allTables.sort(new TableListSorter()); allTables.sort(new TableListSorter());
ArrayList<MatchView> matchList = new ArrayList<>(); List<MatchView> matchList = new ArrayList<>();
ArrayList<TableView> tableList = new ArrayList<>(); List<TableView> tableList = new ArrayList<>();
for (Table table : allTables) { for (Table table : allTables) {
if (table.getState() != TableState.FINISHED) { if (table.getState() != TableState.FINISHED) {
tableList.add(new TableView(table)); tableList.add(new TableView(table));

View file

@ -18,6 +18,7 @@ import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
public enum UserStatsRepository { public enum UserStatsRepository {
@ -107,7 +108,7 @@ public enum UserStatsRepository {
// updateUserStats reads tables finished after the last DB update and reflects it to the DB. // updateUserStats reads tables finished after the last DB update and reflects it to the DB.
// It returns the list of user names that are upated. // It returns the list of user names that are upated.
public List<String> updateUserStats() { public List<String> updateUserStats() {
HashSet<String> updatedUsers = new HashSet<>(); Set<String> updatedUsers = new HashSet<>();
// Lock the DB so that no other updateUserStats runs at the same time. // Lock the DB so that no other updateUserStats runs at the same time.
synchronized(this) { synchronized(this) {
long latestEndTimeMs = this.getLatestEndTimeMs(); long latestEndTimeMs = this.getLatestEndTimeMs();

View file

@ -27,8 +27,10 @@
*/ */
package mage.cards.c; package mage.cards.c;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.DiesTriggeredAbility;
import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.EntersBattlefieldAbility;
import mage.abilities.condition.common.LastTimeCounterRemovedCondition; import mage.abilities.condition.common.LastTimeCounterRemovedCondition;
import mage.abilities.decorator.ConditionalTriggeredAbility; import mage.abilities.decorator.ConditionalTriggeredAbility;
@ -43,9 +45,6 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.counters.CounterType; import mage.counters.CounterType;
import java.util.UUID;
import mage.abilities.common.DiesTriggeredAbility;
/** /**
* *
* @author Gal Lerman * @author Gal Lerman
@ -61,14 +60,14 @@ public class Chronozoa extends CardImpl {
// Flying // Flying
this.addAbility(FlyingAbility.getInstance()); this.addAbility(FlyingAbility.getInstance());
// Vanishing 3 // Vanishing 3 (This permanent enters the battlefield with three time counters on it. At the beginning of your upkeep, remove a time counter from it. When the last is removed, sacrifice it.)
Ability ability = new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.TIME.createInstance(3))); Ability ability = new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.TIME.createInstance(3)));
ability.setRuleVisible(false); ability.setRuleVisible(false);
this.addAbility(ability); this.addAbility(ability);
this.addAbility(new VanishingUpkeepAbility(3)); this.addAbility(new VanishingUpkeepAbility(3));
this.addAbility(new VanishingSacrificeAbility()); this.addAbility(new VanishingSacrificeAbility());
// When Chronozoa is put into a graveyard from play, if it had no time counters on it, create two tokens that are copies of it. // When Chronozoa is put into a graveyard from play, if it had no time counters on it, create two tokens that are copies of it.
Effect effect = new PutTokenOntoBattlefieldCopySourceEffect(2); Effect effect = new PutTokenOntoBattlefieldCopySourceEffect(2);
effect.setText("create two tokens that are copies of it"); effect.setText("create two tokens that are copies of it");

View file

@ -28,13 +28,13 @@
package mage.cards.k; package mage.cards.k;
import java.util.UUID; import java.util.UUID;
import mage.constants.CardType;
import mage.MageInt; import mage.MageInt;
import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.GainLifeEffect;
import mage.abilities.keyword.PersistAbility; import mage.abilities.keyword.PersistAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType;
/** /**
* *
@ -43,7 +43,7 @@ import mage.cards.CardSetInfo;
public class KitchenFinks extends CardImpl { public class KitchenFinks extends CardImpl {
public KitchenFinks(UUID ownerId, CardSetInfo setInfo) { public KitchenFinks(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G/W}{G/W}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G/W}{G/W}");
this.subtype.add("Ouphe"); this.subtype.add("Ouphe");
this.power = new MageInt(3); this.power = new MageInt(3);
@ -51,7 +51,7 @@ public class KitchenFinks extends CardImpl {
// When Kitchen Finks enters the battlefield, you gain 2 life. // When Kitchen Finks enters the battlefield, you gain 2 life.
this.addAbility(new EntersBattlefieldTriggeredAbility(new GainLifeEffect(2))); this.addAbility(new EntersBattlefieldTriggeredAbility(new GainLifeEffect(2)));
// Persist // Persist (When this creature dies, if it had no -1/-1 counters on it, return it to the battlefield under its owner's control with a -1/-1 counter on it.)
this.addAbility(new PersistAbility()); this.addAbility(new PersistAbility());
} }

View file

@ -28,7 +28,6 @@
package mage.cards.r; package mage.cards.r;
import mage.Mana; import mage.Mana;
import mage.abilities.condition.common.LandfallCondition;
import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.decorator.ConditionalManaEffect; import mage.abilities.decorator.ConditionalManaEffect;
import mage.abilities.effects.common.BasicManaEffect; import mage.abilities.effects.common.BasicManaEffect;
@ -37,9 +36,10 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Zone; import mage.constants.Zone;
import mage.watchers.common.LandfallWatcher;
import java.util.UUID; import java.util.UUID;
import mage.abilities.condition.common.PlayLandCondition;
import mage.watchers.common.PlayLandWatcher;
/** /**
* *
@ -48,16 +48,16 @@ import java.util.UUID;
public class RiverOfTears extends CardImpl { public class RiverOfTears extends CardImpl {
public RiverOfTears(UUID ownerId, CardSetInfo setInfo) { public RiverOfTears(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.LAND},""); super(ownerId, setInfo, new CardType[]{CardType.LAND}, "");
// {T}: Add {U} to your mana pool. If you played a land this turn, add {B} to your mana pool instead. // {T}: Add {U} to your mana pool. If you played a land this turn, add {B} to your mana pool instead.
this.addAbility(new ConditionalManaAbility(Zone.BATTLEFIELD, new ConditionalManaEffect( this.addAbility(new ConditionalManaAbility(Zone.BATTLEFIELD, new ConditionalManaEffect(
new BasicManaEffect(Mana.BlackMana(1)), new BasicManaEffect(Mana.BlackMana(1)),
new BasicManaEffect(Mana.BlueMana(1)), new BasicManaEffect(Mana.BlueMana(1)),
LandfallCondition.instance, PlayLandCondition.instance,
"Add {U} to your mana pool. If you played a land this turn, add {B} to your mana pool instead"), "Add {U} to your mana pool. If you played a land this turn, add {B} to your mana pool instead"),
new TapSourceCost()), new TapSourceCost()),
new LandfallWatcher()); new PlayLandWatcher());
} }
public RiverOfTears(final RiverOfTears card) { public RiverOfTears(final RiverOfTears card) {

View file

@ -68,7 +68,7 @@ public class SandStrangler extends CardImpl {
// When Sand Strangler enters the battlefield, if you control a Desert or there is a Desert card in your graveyard, you may have Sand Strangler deal 3 damage to target creature. // When Sand Strangler enters the battlefield, if you control a Desert or there is a Desert card in your graveyard, you may have Sand Strangler deal 3 damage to target creature.
Ability ability = new ConditionalTriggeredAbility( Ability ability = new ConditionalTriggeredAbility(
new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(3)), new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(3), true),
new OrCondition( new OrCondition(
new PermanentsOnTheBattlefieldCondition(new FilterControlledPermanent(filterDesertPermanent)), new PermanentsOnTheBattlefieldCondition(new FilterControlledPermanent(filterDesertPermanent)),
new CardsInControllerGraveCondition(1, filterDesertCard)), new CardsInControllerGraveCondition(1, filterDesertCard)),

View file

@ -60,7 +60,7 @@ public class Terastodon extends CardImpl {
} }
public Terastodon(UUID ownerId, CardSetInfo setInfo) { public Terastodon(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{6}{G}{G}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{6}{G}{G}");
this.subtype.add("Elephant"); this.subtype.add("Elephant");
this.power = new MageInt(9); this.power = new MageInt(9);
@ -112,6 +112,7 @@ class TerastodonEffect extends OneShotEffect {
} }
} }
} }
game.applyEffects();
ElephantToken elephantToken = new ElephantToken(); ElephantToken elephantToken = new ElephantToken();
for (Entry<UUID, Integer> entry : destroyedPermanents.entrySet()) { for (Entry<UUID, Integer> entry : destroyedPermanents.entrySet()) {
elephantToken.putOntoBattlefield(entry.getValue(), game, source.getSourceId(), entry.getKey()); elephantToken.putOntoBattlefield(entry.getValue(), game, source.getSourceId(), entry.getKey());

View file

@ -27,9 +27,6 @@
*/ */
package mage.cards.t; package mage.cards.t;
import java.util.HashSet;
import java.util.Map;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
@ -49,6 +46,10 @@ import mage.game.Game;
import mage.game.combat.CombatGroup; import mage.game.combat.CombatGroup;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
/** /**
* *
* @author LevelX2 * @author LevelX2
@ -113,7 +114,7 @@ class CantBeBlockedUnlessAllEffect extends RestrictionEffect {
return false; return false;
} }
// check blocker restrictions // check blocker restrictions
for (Map.Entry<RestrictionEffect, HashSet<Ability>> entry: game.getContinuousEffects().getApplicableRestrictionEffects(permanent, game).entrySet()) { for (Map.Entry<RestrictionEffect, Set<Ability>> entry: game.getContinuousEffects().getApplicableRestrictionEffects(permanent, game).entrySet()) {
for (Ability ability : entry.getValue()) { for (Ability ability : entry.getValue()) {
if (!entry.getKey().canBlock(attacker, permanent, ability, game)) { if (!entry.getKey().canBlock(attacker, permanent, ability, game)) {
return false; return false;
@ -121,7 +122,7 @@ class CantBeBlockedUnlessAllEffect extends RestrictionEffect {
} }
} }
// check also attacker's restriction effects // check also attacker's restriction effects
for (Map.Entry<RestrictionEffect, HashSet<Ability>> restrictionEntry: game.getContinuousEffects().getApplicableRestrictionEffects(attacker, game).entrySet()) { for (Map.Entry<RestrictionEffect, Set<Ability>> restrictionEntry: game.getContinuousEffects().getApplicableRestrictionEffects(attacker, game).entrySet()) {
for (Ability ability : restrictionEntry.getValue()) { for (Ability ability : restrictionEntry.getValue()) {
if (!(restrictionEntry.getKey() instanceof CantBeBlockedUnlessAllEffect) if (!(restrictionEntry.getKey() instanceof CantBeBlockedUnlessAllEffect)
&& !restrictionEntry.getKey().canBeBlocked(attacker, permanent, ability, game)) { && !restrictionEntry.getKey().canBeBlocked(attacker, permanent, ability, game)) {

View file

@ -1,16 +1,16 @@
/* /*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modification, are * Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met: * permitted provided that the following conditions are met:
* *
* 1. Redistributions of source code must retain the above copyright notice, this list of * 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer. * conditions and the following disclaimer.
* *
* 2. Redistributions in binary form must reproduce the above copyright notice, this list * 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 * of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution. * provided with the distribution.
* *
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * 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 * 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 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
@ -20,23 +20,22 @@
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * 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 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* The views and conclusions contained in the software and documentation are those of the * 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 * authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com. * or implied, of BetaSteward_at_googlemail.com.
*/ */
package mage.cards.v; package mage.cards.v;
import java.util.UUID; import java.util.UUID;
import mage.constants.CardType;
import mage.constants.Zone;
import mage.MageInt; import mage.MageInt;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.common.SacrificeTargetCost;
import mage.abilities.effects.keyword.ScryEffect; import mage.abilities.effects.keyword.ScryEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Zone;
import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetControlledCreaturePermanent;
/** /**
@ -46,13 +45,13 @@ import mage.target.common.TargetControlledCreaturePermanent;
public class VisceraSeer extends CardImpl { public class VisceraSeer extends CardImpl {
public VisceraSeer(UUID ownerId, CardSetInfo setInfo) { public VisceraSeer(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{B}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}");
this.subtype.add("Vampire"); this.subtype.add("Vampire");
this.subtype.add("Wizard"); this.subtype.add("Wizard");
this.power = new MageInt(1); this.power = new MageInt(1);
this.toughness = new MageInt(1); this.toughness = new MageInt(1);
// Sacrifice a creature: Scry 1. (To scry 1, look at the top card of your library, then you may put that card on the bottom of your library.)
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new ScryEffect(1), new SacrificeTargetCost(new TargetControlledCreaturePermanent()))); this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new ScryEffect(1), new SacrificeTargetCost(new TargetControlledCreaturePermanent())));
} }

View file

@ -153,4 +153,36 @@ public class AddingCountersToPermanentsTest extends CardTestPlayerBase {
assertPowerToughness(playerB, "Silvercoat Lion", 2, 2); assertPowerToughness(playerB, "Silvercoat Lion", 2, 2);
} }
/**
* Considering rule 121.6 Persist is not working with Hapatra, Vizier of
* Poisons and Obelisk Spider. Hapatra and Obelisk Spider do not trigger
* their second abilities when Kitchen Finks returns with -1/-1 counter.
*/
@Test
public void HapatraVizierOfPoisons() {
// Whenever Hapatra, Vizier of Poisons deals combat damage to a player, you may put a -1/-1 counter on target creature.
// Whenever you put one or more -1/-1 counters on a creature, create a 1/1 green Snake creature token with deathtouch.
addCard(Zone.BATTLEFIELD, playerA, "Hapatra, Vizier of Poisons", 1);
// When Kitchen Finks enters the battlefield, you gain 2 life.
// Persist (When this creature dies, if it had no -1/-1 counters on it, return it to the battlefield under its owner's control with a -1/-1 counter on it.)
addCard(Zone.BATTLEFIELD, playerA, "Kitchen Finks", 1); // Creature 3/2
addCard(Zone.HAND, playerB, "Lightning Bolt");
addCard(Zone.BATTLEFIELD, playerB, "Mountain");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Bolt", "Kitchen Finks");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertGraveyardCount(playerB, "Lightning Bolt", 1);
assertPowerToughness(playerA, "Kitchen Finks", 2, 1);
assertPermanentCount(playerA, "Snake", 1);
}
} }

View file

@ -0,0 +1,73 @@
package org.mage.test.cards.triggers.dies;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/*
* 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.
*/
/**
*
* @author LevelX2
*/
public class ChronozoaTest extends CardTestPlayerBase {
/**
* Chronozoa's duplicating ability is triggering whenever any card is put
* into a graveyard from play, not just Chronozoa itself. Here's an excerpt
* from the log: As you can see, I sacrificed Viscera Seer and for some
* reason that triggered Chronozoa's ability.
*/
@Test
public void testTriggerOtherCreature() {
addCard(Zone.BATTLEFIELD, playerA, "Island", 4);
// Flying
// Vanishing 3 (This permanent enters the battlefield with three time counters on it. At the beginning of your upkeep, remove a time counter from it. When the last is removed, sacrifice it.)
// When Chronozoa is put into a graveyard from play, if it had no time counters on it, create two tokens that are copies of it.
addCard(Zone.HAND, playerA, "Chronozoa"); // {3}{U}
addCard(Zone.GRAVEYARD, playerA, "Chronozoa");
// Sacrifice a creature: Scry 1. (To scry 1, look at the top card of your library, then you may put that card on the bottom of your library.)
addCard(Zone.BATTLEFIELD, playerA, "Viscera Seer", 1);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Chronozoa");
activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Sacrifice a creature");
addTarget(playerA, "Viscera Seer");
setStopAt(1, PhaseStep.END_TURN);
execute();
assertGraveyardCount(playerA, "Viscera Seer", 1);
assertGraveyardCount(playerA, "Chronozoa", 1);
assertPermanentCount(playerA, "Chronozoa", 1);
assertPermanentCount(playerA, 5);
assertHandCount(playerA, 0);
}
}

View file

@ -27,19 +27,9 @@
*/ */
package org.mage.test.player; package org.mage.test.player;
import java.io.Serializable;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import mage.MageObject; import mage.MageObject;
import mage.MageObjectReference; import mage.MageObjectReference;
import mage.abilities.Abilities; import mage.abilities.*;
import mage.abilities.Ability;
import mage.abilities.ActivatedAbility;
import mage.abilities.Mode;
import mage.abilities.Modes;
import mage.abilities.SpellAbility;
import mage.abilities.TriggeredAbility;
import mage.abilities.costs.AlternativeSourceCosts; import mage.abilities.costs.AlternativeSourceCosts;
import mage.abilities.costs.Cost; import mage.abilities.costs.Cost;
import mage.abilities.costs.Costs; import mage.abilities.costs.Costs;
@ -52,13 +42,7 @@ import mage.cards.Card;
import mage.cards.Cards; import mage.cards.Cards;
import mage.cards.decks.Deck; import mage.cards.decks.Deck;
import mage.choices.Choice; import mage.choices.Choice;
import mage.constants.AbilityType; import mage.constants.*;
import mage.constants.ManaType;
import mage.constants.Outcome;
import mage.constants.PhaseStep;
import mage.constants.RangeOfInfluence;
import mage.constants.SpellAbilityType;
import mage.constants.Zone;
import mage.counters.Counter; import mage.counters.Counter;
import mage.counters.Counters; import mage.counters.Counters;
import mage.filter.Filter; import mage.filter.Filter;
@ -83,22 +67,15 @@ import mage.players.Library;
import mage.players.ManaPool; import mage.players.ManaPool;
import mage.players.Player; import mage.players.Player;
import mage.players.net.UserData; import mage.players.net.UserData;
import mage.target.Target; import mage.target.*;
import mage.target.TargetAmount; import mage.target.common.*;
import mage.target.TargetCard;
import mage.target.TargetPermanent;
import mage.target.TargetPlayer;
import mage.target.TargetSource;
import mage.target.TargetSpell;
import mage.target.common.TargetCardInHand;
import mage.target.common.TargetCardInLibrary;
import mage.target.common.TargetCardInOpponentsGraveyard;
import mage.target.common.TargetCardInYourGraveyard;
import mage.target.common.TargetCreatureOrPlayer;
import mage.target.common.TargetCreaturePermanentAmount;
import mage.target.common.TargetPermanentOrPlayer;
import org.junit.Ignore; import org.junit.Ignore;
import java.io.Serializable;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/** /**
* @author BetaSteward_at_googlemail.com * @author BetaSteward_at_googlemail.com
* @author Simown * @author Simown
@ -1329,7 +1306,7 @@ public class TestPlayer implements Player {
} }
@Override @Override
public int drawCards(int num, Game game, ArrayList<UUID> appliedEffects) { public int drawCards(int num, Game game, List<UUID> appliedEffects) {
return computerPlayer.drawCards(num, game, appliedEffects); return computerPlayer.drawCards(num, game, appliedEffects);
} }
@ -1619,7 +1596,7 @@ public class TestPlayer implements Player {
} }
@Override @Override
public int damage(int damage, UUID sourceId, Game game, boolean combatDamage, boolean preventable, ArrayList<UUID> appliedEffects) { public int damage(int damage, UUID sourceId, Game game, boolean combatDamage, boolean preventable, List<UUID> appliedEffects) {
return computerPlayer.damage(damage, sourceId, game, combatDamage, preventable, appliedEffects); return computerPlayer.damage(damage, sourceId, game, combatDamage, preventable, appliedEffects);
} }
@ -2284,7 +2261,7 @@ public class TestPlayer implements Player {
} }
@Override @Override
public boolean moveCards(Card card, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, ArrayList<UUID> appliedEffects) { public boolean moveCards(Card card, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, List<UUID> appliedEffects) {
return computerPlayer.moveCards(card, toZone, source, game, tapped, faceDown, byOwner, appliedEffects); return computerPlayer.moveCards(card, toZone, source, game, tapped, faceDown, byOwner, appliedEffects);
} }
@ -2299,7 +2276,7 @@ public class TestPlayer implements Player {
} }
@Override @Override
public boolean moveCards(Set<Card> cards, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, ArrayList<UUID> appliedEffects) { public boolean moveCards(Set<Card> cards, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, List<UUID> appliedEffects) {
return computerPlayer.moveCards(cards, toZone, source, game, tapped, faceDown, byOwner, appliedEffects); return computerPlayer.moveCards(cards, toZone, source, game, tapped, faceDown, byOwner, appliedEffects);
} }

View file

@ -27,21 +27,8 @@
*/ */
package org.mage.test.stub; package org.mage.test.stub;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import mage.MageObject; import mage.MageObject;
import mage.abilities.Abilities; import mage.abilities.*;
import mage.abilities.Ability;
import mage.abilities.ActivatedAbility;
import mage.abilities.Mode;
import mage.abilities.Modes;
import mage.abilities.SpellAbility;
import mage.abilities.TriggeredAbility;
import mage.abilities.costs.AlternativeSourceCosts; import mage.abilities.costs.AlternativeSourceCosts;
import mage.abilities.costs.Cost; import mage.abilities.costs.Cost;
import mage.abilities.costs.Costs; import mage.abilities.costs.Costs;
@ -53,12 +40,7 @@ import mage.cards.Card;
import mage.cards.Cards; import mage.cards.Cards;
import mage.cards.decks.Deck; import mage.cards.decks.Deck;
import mage.choices.Choice; import mage.choices.Choice;
import mage.constants.AbilityType; import mage.constants.*;
import mage.constants.ManaType;
import mage.constants.Outcome;
import mage.constants.PlayerAction;
import mage.constants.RangeOfInfluence;
import mage.constants.Zone;
import mage.counters.Counter; import mage.counters.Counter;
import mage.counters.Counters; import mage.counters.Counters;
import mage.filter.FilterPermanent; import mage.filter.FilterPermanent;
@ -80,6 +62,9 @@ import mage.target.TargetAmount;
import mage.target.TargetCard; import mage.target.TargetCard;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
import java.io.Serializable;
import java.util.*;
/** /**
* *
* @author Quercitron * @author Quercitron
@ -174,7 +159,7 @@ public class PlayerStub implements Player {
} }
@Override @Override
public int damage(int damage, UUID sourceId, Game game, boolean combatDamage, boolean preventable, ArrayList<UUID> appliedEffects) { public int damage(int damage, UUID sourceId, Game game, boolean combatDamage, boolean preventable, List<UUID> appliedEffects) {
return 0; return 0;
} }
@ -563,7 +548,7 @@ public class PlayerStub implements Player {
} }
@Override @Override
public int drawCards(int num, Game game, ArrayList<UUID> appliedEffects) { public int drawCards(int num, Game game, List<UUID> appliedEffects) {
return 0; return 0;
} }
@ -1098,7 +1083,7 @@ public class PlayerStub implements Player {
} }
@Override @Override
public boolean moveCards(Card card, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, ArrayList<UUID> appliedEffects) { public boolean moveCards(Card card, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, List<UUID> appliedEffects) {
return false; return false;
} }
@ -1113,7 +1098,7 @@ public class PlayerStub implements Player {
} }
@Override @Override
public boolean moveCards(Set<Card> cards, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, ArrayList<UUID> appliedEffects) { public boolean moveCards(Set<Card> cards, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, List<UUID> appliedEffects) {
return false; return false;
} }

View file

@ -28,9 +28,6 @@
package mage.abilities.common; package mage.abilities.common;
import java.util.ArrayList;
import java.util.Set;
import mage.MageObject; import mage.MageObject;
import mage.abilities.ActivatedAbilityImpl; import mage.abilities.ActivatedAbilityImpl;
import mage.abilities.costs.common.PayLifeCost; import mage.abilities.costs.common.PayLifeCost;
@ -48,6 +45,10 @@ import mage.filter.predicate.mageobject.CardTypePredicate;
import mage.filter.predicate.mageobject.SubtypePredicate; import mage.filter.predicate.mageobject.SubtypePredicate;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/** /**
* *
* @author BetaSteward_at_googlemail.com * @author BetaSteward_at_googlemail.com
@ -67,7 +68,7 @@ public class FetchLandActivatedAbility extends ActivatedAbilityImpl {
addCost(new SacrificeSourceCost()); addCost(new SacrificeSourceCost());
FilterCard filter = new FilterCard(subTypeNames(subtypes)); FilterCard filter = new FilterCard(subTypeNames(subtypes));
filter.add(new CardTypePredicate(CardType.LAND)); filter.add(new CardTypePredicate(CardType.LAND));
ArrayList<Predicate<MageObject>> subtypePredicates = new ArrayList<>(); List<Predicate<MageObject>> subtypePredicates = new ArrayList<>();
for (SubType subtype : subtypes) { for (SubType subtype : subtypes) {
subtypePredicates.add(new SubtypePredicate(subtype)); subtypePredicates.add(new SubtypePredicate(subtype));
} }

View file

@ -0,0 +1,20 @@
package mage.abilities.condition.common;
import mage.abilities.Ability;
import mage.abilities.condition.Condition;
import mage.game.Game;
import mage.watchers.common.PlayLandWatcher;
/**
* @author jeffwadsworth
*/
public enum PlayLandCondition implements Condition {
instance;
@Override
public boolean apply(Game game, Ability source) {
PlayLandWatcher watcher = (PlayLandWatcher) game.getState().getWatchers().get(PlayLandWatcher.class.getSimpleName());
return watcher != null
&& watcher.landPlayed(source.getControllerId());
}
}

View file

@ -27,13 +27,15 @@
*/ */
package mage.abilities.condition.common; package mage.abilities.condition.common;
import java.util.ArrayList;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.condition.Condition; import mage.abilities.condition.Condition;
import mage.abilities.keyword.SurgeAbility; import mage.abilities.keyword.SurgeAbility;
import mage.constants.AbilityType; import mage.constants.AbilityType;
import mage.game.Game; import mage.game.Game;
import java.util.ArrayList;
import java.util.List;
/** /**
* *
* @author LevelX2 * @author LevelX2
@ -46,7 +48,7 @@ public enum SurgedCondition implements Condition {
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
if (source.getAbilityType() == AbilityType.TRIGGERED) { if (source.getAbilityType() == AbilityType.TRIGGERED) {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
ArrayList<Integer> surgeActivations = (ArrayList) game.getState().getValue(SurgeAbility.SURGE_ACTIVATION_VALUE_KEY + source.getSourceId()); List<Integer> surgeActivations = (ArrayList) game.getState().getValue(SurgeAbility.SURGE_ACTIVATION_VALUE_KEY + source.getSourceId());
if (surgeActivations != null) { if (surgeActivations != null) {
return surgeActivations.contains(game.getState().getZoneChangeCounter(source.getSourceId()) - 1); return surgeActivations.contains(game.getState().getZoneChangeCounter(source.getSourceId()) - 1);
} }

View file

@ -27,11 +27,6 @@
*/ */
package mage.abilities.effects; package mage.abilities.effects;
import java.io.Serializable;
import java.util.*;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import mage.MageObject; import mage.MageObject;
import mage.abilities.*; import mage.abilities.*;
import mage.abilities.keyword.SpliceOntoArcaneAbility; import mage.abilities.keyword.SpliceOntoArcaneAbility;
@ -54,6 +49,11 @@ import mage.players.Player;
import mage.target.common.TargetCardInHand; import mage.target.common.TargetCardInHand;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import java.io.Serializable;
import java.util.*;
import java.util.Map.Entry;
import java.util.stream.Collectors;
/** /**
* @author BetaSteward_at_googlemail.com * @author BetaSteward_at_googlemail.com
*/ */
@ -192,7 +192,7 @@ public class ContinuousEffects implements Serializable {
case WhileOnBattlefield: case WhileOnBattlefield:
case WhileOnStack: case WhileOnStack:
case WhileInGraveyard: case WhileInGraveyard:
HashSet<Ability> abilities = layeredEffects.getAbility(effect.getId()); Set<Ability> abilities = layeredEffects.getAbility(effect.getId());
if (!abilities.isEmpty()) { if (!abilities.isEmpty()) {
for (Ability ability : abilities) { for (Ability ability : abilities) {
// If e.g. triggerd abilities (non static) created the effect, the ability must not be in usable zone (e.g. Unearth giving Haste effect) // If e.g. triggerd abilities (non static) created the effect, the ability must not be in usable zone (e.g. Unearth giving Haste effect)
@ -244,11 +244,11 @@ public class ContinuousEffects implements Serializable {
return effects.stream().filter(effect->effect.hasLayer(layer)).collect(Collectors.toList()); return effects.stream().filter(effect->effect.hasLayer(layer)).collect(Collectors.toList());
} }
public HashMap<RequirementEffect, HashSet<Ability>> getApplicableRequirementEffects(Permanent permanent, Game game) { public Map<RequirementEffect, Set<Ability>> getApplicableRequirementEffects(Permanent permanent, Game game) {
HashMap<RequirementEffect, HashSet<Ability>> effects = new HashMap<>(); Map<RequirementEffect, Set<Ability>> effects = new HashMap<>();
for (RequirementEffect effect : requirementEffects) { for (RequirementEffect effect : requirementEffects) {
HashSet<Ability> abilities = requirementEffects.getAbility(effect.getId()); Set<Ability> abilities = requirementEffects.getAbility(effect.getId());
HashSet<Ability> applicableAbilities = new HashSet<>(); Set<Ability> applicableAbilities = new HashSet<>();
for (Ability ability : abilities) { for (Ability ability : abilities) {
if (!(ability instanceof StaticAbility) || ability.isInUseableZone(game, ability instanceof MageSingleton ? permanent : null, null)) { if (!(ability instanceof StaticAbility) || ability.isInUseableZone(game, ability instanceof MageSingleton ? permanent : null, null)) {
if (effect.applies(permanent, ability, game)) { if (effect.applies(permanent, ability, game)) {
@ -263,11 +263,11 @@ public class ContinuousEffects implements Serializable {
return effects; return effects;
} }
public HashMap<RestrictionEffect, HashSet<Ability>> getApplicableRestrictionEffects(Permanent permanent, Game game) { public Map<RestrictionEffect, Set<Ability>> getApplicableRestrictionEffects(Permanent permanent, Game game) {
HashMap<RestrictionEffect, HashSet<Ability>> effects = new HashMap<>(); Map<RestrictionEffect, Set<Ability>> effects = new HashMap<>();
for (RestrictionEffect effect : restrictionEffects) { for (RestrictionEffect effect : restrictionEffects) {
HashSet<Ability> abilities = restrictionEffects.getAbility(effect.getId()); Set<Ability> abilities = restrictionEffects.getAbility(effect.getId());
HashSet<Ability> applicableAbilities = new HashSet<>(); Set<Ability> applicableAbilities = new HashSet<>();
for (Ability ability : abilities) { for (Ability ability : abilities) {
if (!(ability instanceof StaticAbility) || ability.isInUseableZone(game, ability instanceof MageSingleton ? permanent : null, null)) { if (!(ability instanceof StaticAbility) || ability.isInUseableZone(game, ability instanceof MageSingleton ? permanent : null, null)) {
if (effect.applies(permanent, ability, game)) { if (effect.applies(permanent, ability, game)) {
@ -282,11 +282,11 @@ public class ContinuousEffects implements Serializable {
return effects; return effects;
} }
public HashMap<RestrictionUntapNotMoreThanEffect, HashSet<Ability>> getApplicableRestrictionUntapNotMoreThanEffects(Player player, Game game) { public Map<RestrictionUntapNotMoreThanEffect, Set<Ability>> getApplicableRestrictionUntapNotMoreThanEffects(Player player, Game game) {
HashMap<RestrictionUntapNotMoreThanEffect, HashSet<Ability>> effects = new HashMap<>(); Map<RestrictionUntapNotMoreThanEffect, Set<Ability>> effects = new HashMap<>();
for (RestrictionUntapNotMoreThanEffect effect : restrictionUntapNotMoreThanEffects) { for (RestrictionUntapNotMoreThanEffect effect : restrictionUntapNotMoreThanEffects) {
HashSet<Ability> abilities = restrictionUntapNotMoreThanEffects.getAbility(effect.getId()); Set<Ability> abilities = restrictionUntapNotMoreThanEffects.getAbility(effect.getId());
HashSet<Ability> applicableAbilities = new HashSet<>(); Set<Ability> applicableAbilities = new HashSet<>();
for (Ability ability : abilities) { for (Ability ability : abilities) {
if (!(ability instanceof StaticAbility) || ability.isInUseableZone(game, null, null)) { if (!(ability instanceof StaticAbility) || ability.isInUseableZone(game, null, null)) {
if (effect.applies(player, ability, game)) { if (effect.applies(player, ability, game)) {
@ -307,7 +307,7 @@ public class ContinuousEffects implements Serializable {
continue; continue;
} }
if (effect instanceof PayCostToAttackBlockEffect) { if (effect instanceof PayCostToAttackBlockEffect) {
HashSet<Ability> abilities = replacementEffects.getAbility(effect.getId()); Set<Ability> abilities = replacementEffects.getAbility(effect.getId());
for (Ability ability : abilities) { for (Ability ability : abilities) {
// for replacment effects of static abilities do not use LKI to check if to apply // for replacment effects of static abilities do not use LKI to check if to apply
if (ability.getAbilityType() != AbilityType.STATIC || ability.isInUseableZone(game, null, event)) { if (ability.getAbilityType() != AbilityType.STATIC || ability.isInUseableZone(game, null, event)) {
@ -332,8 +332,8 @@ public class ContinuousEffects implements Serializable {
* @return a list of all {@link ReplacementEffect} that apply to the current * @return a list of all {@link ReplacementEffect} that apply to the current
* event * event
*/ */
private HashMap<ReplacementEffect, HashSet<Ability>> getApplicableReplacementEffects(GameEvent event, Game game) { private Map<ReplacementEffect, Set<Ability>> getApplicableReplacementEffects(GameEvent event, Game game) {
HashMap<ReplacementEffect, HashSet<Ability>> replaceEffects = new HashMap<>(); Map<ReplacementEffect, Set<Ability>> replaceEffects = new HashMap<>();
if (planeswalkerRedirectionEffect.checksEventType(event, game) && planeswalkerRedirectionEffect.applies(event, null, game)) { if (planeswalkerRedirectionEffect.checksEventType(event, game) && planeswalkerRedirectionEffect.applies(event, null, game)) {
replaceEffects.put(planeswalkerRedirectionEffect, null); replaceEffects.put(planeswalkerRedirectionEffect, null);
} }
@ -351,8 +351,8 @@ public class ContinuousEffects implements Serializable {
// TODO: Handle also gained effect that are connected to different abilities. // TODO: Handle also gained effect that are connected to different abilities.
continue; continue;
} }
HashSet<Ability> abilities = replacementEffects.getAbility(effect.getId()); Set<Ability> abilities = replacementEffects.getAbility(effect.getId());
HashSet<Ability> applicableAbilities = new HashSet<>(); Set<Ability> applicableAbilities = new HashSet<>();
for (Ability ability : abilities) { for (Ability ability : abilities) {
// for replacment effects of static abilities do not use LKI to check if to apply // for replacment effects of static abilities do not use LKI to check if to apply
if (ability.getAbilityType() != AbilityType.STATIC || ability.isInUseableZone(game, null, event)) { if (ability.getAbilityType() != AbilityType.STATIC || ability.isInUseableZone(game, null, event)) {
@ -380,8 +380,8 @@ public class ContinuousEffects implements Serializable {
// TODO: Handle also gained effect that are connected to different abilities. // TODO: Handle also gained effect that are connected to different abilities.
continue; continue;
} }
HashSet<Ability> abilities = preventionEffects.getAbility(effect.getId()); Set<Ability> abilities = preventionEffects.getAbility(effect.getId());
HashSet<Ability> applicableAbilities = new HashSet<>(); Set<Ability> applicableAbilities = new HashSet<>();
for (Ability ability : abilities) { for (Ability ability : abilities) {
if (ability.getAbilityType() != AbilityType.STATIC || ability.isInUseableZone(game, null, event)) { if (ability.getAbilityType() != AbilityType.STATIC || ability.isInUseableZone(game, null, event)) {
if (effect.getDuration() != Duration.OneUse || !effect.isUsed()) { if (effect.getDuration() != Duration.OneUse || !effect.isUsed()) {
@ -455,7 +455,7 @@ public class ContinuousEffects implements Serializable {
List<CostModificationEffect> costEffects = new ArrayList<>(); List<CostModificationEffect> costEffects = new ArrayList<>();
for (CostModificationEffect effect : costModificationEffects) { for (CostModificationEffect effect : costModificationEffects) {
HashSet<Ability> abilities = costModificationEffects.getAbility(effect.getId()); Set<Ability> abilities = costModificationEffects.getAbility(effect.getId());
for (Ability ability : abilities) { for (Ability ability : abilities) {
if (!(ability instanceof StaticAbility) || ability.isInUseableZone(game, null, null)) { if (!(ability instanceof StaticAbility) || ability.isInUseableZone(game, null, null)) {
if (effect.getDuration() != Duration.OneUse || !effect.isUsed()) { if (effect.getDuration() != Duration.OneUse || !effect.isUsed()) {
@ -479,7 +479,7 @@ public class ContinuousEffects implements Serializable {
List<SpliceCardEffect> spliceEffects = new ArrayList<>(); List<SpliceCardEffect> spliceEffects = new ArrayList<>();
for (SpliceCardEffect effect : spliceCardEffects) { for (SpliceCardEffect effect : spliceCardEffects) {
HashSet<Ability> abilities = spliceCardEffects.getAbility(effect.getId()); Set<Ability> abilities = spliceCardEffects.getAbility(effect.getId());
for (Ability ability : abilities) { for (Ability ability : abilities) {
if (ability.getControllerId().equals(playerId) && (!(ability instanceof StaticAbility) || ability.isInUseableZone(game, null, null))) { if (ability.getControllerId().equals(playerId) && (!(ability instanceof StaticAbility) || ability.isInUseableZone(game, null, null))) {
if (effect.getDuration() != Duration.OneUse || !effect.isUsed()) { if (effect.getDuration() != Duration.OneUse || !effect.isUsed()) {
@ -500,7 +500,7 @@ public class ContinuousEffects implements Serializable {
public boolean asThough(UUID objectId, AsThoughEffectType type, Ability affectedAbility, UUID controllerId, Game game) { public boolean asThough(UUID objectId, AsThoughEffectType type, Ability affectedAbility, UUID controllerId, Game game) {
List<AsThoughEffect> asThoughEffectsList = getApplicableAsThoughEffects(type, game); List<AsThoughEffect> asThoughEffectsList = getApplicableAsThoughEffects(type, game);
for (AsThoughEffect effect : asThoughEffectsList) { for (AsThoughEffect effect : asThoughEffectsList) {
HashSet<Ability> abilities = asThoughEffectsMap.get(type).getAbility(effect.getId()); Set<Ability> abilities = asThoughEffectsMap.get(type).getAbility(effect.getId());
for (Ability ability : abilities) { for (Ability ability : abilities) {
if (affectedAbility == null) { if (affectedAbility == null) {
if (effect.applies(objectId, ability, controllerId, game)) { if (effect.applies(objectId, ability, controllerId, game)) {
@ -519,7 +519,7 @@ public class ContinuousEffects implements Serializable {
// First check existing only effects // First check existing only effects
List<AsThoughEffect> asThoughEffectsList = getApplicableAsThoughEffects(AsThoughEffectType.SPEND_ONLY_MANA, game); List<AsThoughEffect> asThoughEffectsList = getApplicableAsThoughEffects(AsThoughEffectType.SPEND_ONLY_MANA, game);
for (AsThoughEffect effect : asThoughEffectsList) { for (AsThoughEffect effect : asThoughEffectsList) {
HashSet<Ability> abilities = asThoughEffectsMap.get(AsThoughEffectType.SPEND_ONLY_MANA).getAbility(effect.getId()); Set<Ability> abilities = asThoughEffectsMap.get(AsThoughEffectType.SPEND_ONLY_MANA).getAbility(effect.getId());
for (Ability ability : abilities) { for (Ability ability : abilities) {
if ((affectedAbility == null && effect.applies(objectId, ability, controllerId, game)) if ((affectedAbility == null && effect.applies(objectId, ability, controllerId, game))
|| effect.applies(objectId, affectedAbility, ability, game)) { || effect.applies(objectId, affectedAbility, ability, game)) {
@ -532,7 +532,7 @@ public class ContinuousEffects implements Serializable {
// then check effects that allow to use other mana types to pay the current mana type to pay // then check effects that allow to use other mana types to pay the current mana type to pay
asThoughEffectsList = getApplicableAsThoughEffects(AsThoughEffectType.SPEND_OTHER_MANA, game); asThoughEffectsList = getApplicableAsThoughEffects(AsThoughEffectType.SPEND_OTHER_MANA, game);
for (AsThoughEffect effect : asThoughEffectsList) { for (AsThoughEffect effect : asThoughEffectsList) {
HashSet<Ability> abilities = asThoughEffectsMap.get(AsThoughEffectType.SPEND_OTHER_MANA).getAbility(effect.getId()); Set<Ability> abilities = asThoughEffectsMap.get(AsThoughEffectType.SPEND_OTHER_MANA).getAbility(effect.getId());
for (Ability ability : abilities) { for (Ability ability : abilities) {
if ((affectedAbility == null && effect.applies(objectId, ability, controllerId, game)) if ((affectedAbility == null && effect.applies(objectId, ability, controllerId, game))
|| effect.applies(objectId, affectedAbility, ability, game)) { || effect.applies(objectId, affectedAbility, ability, game)) {
@ -557,7 +557,7 @@ public class ContinuousEffects implements Serializable {
List<AsThoughEffect> asThoughEffectsList = new ArrayList<>(); List<AsThoughEffect> asThoughEffectsList = new ArrayList<>();
if (asThoughEffectsMap.containsKey(type)) { if (asThoughEffectsMap.containsKey(type)) {
for (AsThoughEffect effect : asThoughEffectsMap.get(type)) { for (AsThoughEffect effect : asThoughEffectsMap.get(type)) {
HashSet<Ability> abilities = asThoughEffectsMap.get(type).getAbility(effect.getId()); Set<Ability> abilities = asThoughEffectsMap.get(type).getAbility(effect.getId());
for (Ability ability : abilities) { for (Ability ability : abilities) {
if (!(ability instanceof StaticAbility) || ability.isInUseableZone(game, null, null)) { if (!(ability instanceof StaticAbility) || ability.isInUseableZone(game, null, null)) {
if (effect.getDuration() != Duration.OneUse || !effect.isUsed()) { if (effect.getDuration() != Duration.OneUse || !effect.isUsed()) {
@ -600,7 +600,7 @@ public class ContinuousEffects implements Serializable {
for (CostModificationEffect effect : costEffects) { for (CostModificationEffect effect : costEffects) {
if (effect.getModificationType() == CostModificationType.INCREASE_COST) { if (effect.getModificationType() == CostModificationType.INCREASE_COST) {
HashSet<Ability> abilities = costModificationEffects.getAbility(effect.getId()); Set<Ability> abilities = costModificationEffects.getAbility(effect.getId());
for (Ability ability : abilities) { for (Ability ability : abilities) {
if (effect.applies(abilityToModify, ability, game)) { if (effect.applies(abilityToModify, ability, game)) {
effect.apply(game, ability, abilityToModify); effect.apply(game, ability, abilityToModify);
@ -611,7 +611,7 @@ public class ContinuousEffects implements Serializable {
for (CostModificationEffect effect : costEffects) { for (CostModificationEffect effect : costEffects) {
if (effect.getModificationType() == CostModificationType.REDUCE_COST) { if (effect.getModificationType() == CostModificationType.REDUCE_COST) {
HashSet<Ability> abilities = costModificationEffects.getAbility(effect.getId()); Set<Ability> abilities = costModificationEffects.getAbility(effect.getId());
for (Ability ability : abilities) { for (Ability ability : abilities) {
if (effect.applies(abilityToModify, ability, game)) { if (effect.applies(abilityToModify, ability, game)) {
effect.apply(game, ability, abilityToModify); effect.apply(game, ability, abilityToModify);
@ -622,7 +622,7 @@ public class ContinuousEffects implements Serializable {
for (CostModificationEffect effect : costEffects) { for (CostModificationEffect effect : costEffects) {
if (effect.getModificationType() == CostModificationType.SET_COST) { if (effect.getModificationType() == CostModificationType.SET_COST) {
HashSet<Ability> abilities = costModificationEffects.getAbility(effect.getId()); Set<Ability> abilities = costModificationEffects.getAbility(effect.getId());
for (Ability ability : abilities) { for (Ability ability : abilities) {
if (effect.applies(abilityToModify, ability, game)) { if (effect.applies(abilityToModify, ability, game)) {
effect.apply(game, ability, abilityToModify); effect.apply(game, ability, abilityToModify);
@ -647,7 +647,7 @@ public class ContinuousEffects implements Serializable {
// get the applyable splice abilities // get the applyable splice abilities
List<SpliceOntoArcaneAbility> spliceAbilities = new ArrayList<>(); List<SpliceOntoArcaneAbility> spliceAbilities = new ArrayList<>();
for (SpliceCardEffect effect : spliceEffects) { for (SpliceCardEffect effect : spliceEffects) {
HashSet<Ability> abilities = spliceCardEffects.getAbility(effect.getId()); Set<Ability> abilities = spliceCardEffects.getAbility(effect.getId());
for (Ability ability : abilities) { for (Ability ability : abilities) {
if (effect.applies(abilityToModify, ability, game)) { if (effect.applies(abilityToModify, ability, game)) {
spliceAbilities.add((SpliceOntoArcaneAbility) ability); spliceAbilities.add((SpliceOntoArcaneAbility) ability);
@ -741,14 +741,14 @@ public class ContinuousEffects implements Serializable {
public boolean replaceEvent(GameEvent event, Game game) { public boolean replaceEvent(GameEvent event, Game game) {
boolean caught = false; boolean caught = false;
HashMap<UUID, HashSet<UUID>> consumed = new HashMap<>(); Map<UUID, Set<UUID>> consumed = new HashMap<>();
do { do {
HashMap<ReplacementEffect, HashSet<Ability>> rEffects = getApplicableReplacementEffects(event, game); Map<ReplacementEffect, Set<Ability>> rEffects = getApplicableReplacementEffects(event, game);
// Remove all consumed effects (ability dependant) // Remove all consumed effects (ability dependant)
for (Iterator<ReplacementEffect> it1 = rEffects.keySet().iterator(); it1.hasNext();) { for (Iterator<ReplacementEffect> it1 = rEffects.keySet().iterator(); it1.hasNext();) {
ReplacementEffect entry = it1.next(); ReplacementEffect entry = it1.next();
if (consumed.containsKey(entry.getId())) { if (consumed.containsKey(entry.getId())) {
HashSet<UUID> consumedAbilitiesIds = consumed.get(entry.getId()); Set<UUID> consumedAbilitiesIds = consumed.get(entry.getId());
if (rEffects.get(entry) == null || consumedAbilitiesIds.size() == rEffects.get(entry).size()) { if (rEffects.get(entry) == null || consumedAbilitiesIds.size() == rEffects.get(entry).size()) {
it1.remove(); it1.remove();
} else { } else {
@ -770,7 +770,7 @@ public class ContinuousEffects implements Serializable {
boolean onlyOne = false; boolean onlyOne = false;
if (rEffects.size() == 1) { if (rEffects.size() == 1) {
ReplacementEffect effect = rEffects.keySet().iterator().next(); ReplacementEffect effect = rEffects.keySet().iterator().next();
HashSet<Ability> abilities; Set<Ability> abilities;
if (effect.getEffectType() == EffectType.REPLACEMENT) { if (effect.getEffectType() == EffectType.REPLACEMENT) {
abilities = replacementEffects.getAbility(effect.getId()); abilities = replacementEffects.getAbility(effect.getId());
} else { } else {
@ -791,7 +791,7 @@ public class ContinuousEffects implements Serializable {
int checked = 0; int checked = 0;
ReplacementEffect rEffect = null; ReplacementEffect rEffect = null;
Ability rAbility = null; Ability rAbility = null;
for (Map.Entry<ReplacementEffect, HashSet<Ability>> entry : rEffects.entrySet()) { for (Map.Entry<ReplacementEffect, Set<Ability>> entry : rEffects.entrySet()) {
if (entry.getValue() == null) { if (entry.getValue() == null) {
if (checked == index) { if (checked == index) {
rEffect = entry.getKey(); rEffect = entry.getKey();
@ -800,7 +800,7 @@ public class ContinuousEffects implements Serializable {
checked++; checked++;
} }
} else { } else {
HashSet<Ability> abilities = entry.getValue(); Set<Ability> abilities = entry.getValue();
int size = abilities.size(); int size = abilities.size();
if (index > (checked + size - 1)) { if (index > (checked + size - 1)) {
checked += size; checked += size;
@ -831,13 +831,13 @@ public class ContinuousEffects implements Serializable {
// add the applied effect to the consumed effects // add the applied effect to the consumed effects
if (rEffect != null) { if (rEffect != null) {
if (consumed.containsKey(rEffect.getId())) { if (consumed.containsKey(rEffect.getId())) {
HashSet<UUID> set = consumed.get(rEffect.getId()); Set<UUID> set = consumed.get(rEffect.getId());
if (rAbility != null) { if (rAbility != null) {
set.add(rAbility.getId()); set.add(rAbility.getId());
} }
} else { } else {
HashSet<UUID> set = new HashSet<>(); Set<UUID> set = new HashSet<>();
if (rAbility != null) { // in case of AuraReplacementEffect or PlaneswalkerReplacementEffect there is no Ability if (rAbility != null) { // in case of AuraReplacementEffect or PlaneswalkerReplacementEffect there is no Ability
set.add(rAbility.getId()); set.add(rAbility.getId());
} }
@ -860,7 +860,7 @@ public class ContinuousEffects implements Serializable {
List<ContinuousEffect> layer = filterLayeredEffects(activeLayerEffects, Layer.CopyEffects_1); List<ContinuousEffect> layer = filterLayeredEffects(activeLayerEffects, Layer.CopyEffects_1);
for (ContinuousEffect effect : layer) { for (ContinuousEffect effect : layer) {
HashSet<Ability> abilities = layeredEffects.getAbility(effect.getId()); Set<Ability> abilities = layeredEffects.getAbility(effect.getId());
for (Ability ability : abilities) { for (Ability ability : abilities) {
effect.apply(Layer.CopyEffects_1, SubLayer.NA, ability, game); effect.apply(Layer.CopyEffects_1, SubLayer.NA, ability, game);
} }
@ -876,7 +876,7 @@ public class ContinuousEffects implements Serializable {
// e.g. Mind Control is controlled by Steal Enchantment // e.g. Mind Control is controlled by Steal Enchantment
while (true) { while (true) {
for (ContinuousEffect effect : layer) { for (ContinuousEffect effect : layer) {
HashSet<Ability> abilities = layeredEffects.getAbility(effect.getId()); Set<Ability> abilities = layeredEffects.getAbility(effect.getId());
for (Ability ability : abilities) { for (Ability ability : abilities) {
effect.apply(Layer.ControlChangingEffects_2, SubLayer.NA, ability, game); effect.apply(Layer.ControlChangingEffects_2, SubLayer.NA, ability, game);
} }
@ -908,7 +908,7 @@ public class ContinuousEffects implements Serializable {
continue; continue;
} }
List<Ability> appliedAbilities = appliedEffectAbilities.get(effect); List<Ability> appliedAbilities = appliedEffectAbilities.get(effect);
HashSet<Ability> abilities = layeredEffects.getAbility(effect.getId()); Set<Ability> abilities = layeredEffects.getAbility(effect.getId());
for (Ability ability : abilities) { for (Ability ability : abilities) {
if (appliedAbilities == null || !appliedAbilities.contains(ability)) { if (appliedAbilities == null || !appliedAbilities.contains(ability)) {
if (appliedAbilities == null) { if (appliedAbilities == null) {
@ -955,7 +955,7 @@ public class ContinuousEffects implements Serializable {
layer = filterLayeredEffects(activeLayerEffects, Layer.PTChangingEffects_7); layer = filterLayeredEffects(activeLayerEffects, Layer.PTChangingEffects_7);
for (ContinuousEffect effect : layer) { for (ContinuousEffect effect : layer) {
HashSet<Ability> abilities = layeredEffects.getAbility(effect.getId()); Set<Ability> abilities = layeredEffects.getAbility(effect.getId());
for (Ability ability : abilities) { for (Ability ability : abilities) {
if (abilityActive(ability, game)) { if (abilityActive(ability, game)) {
effect.apply(Layer.PTChangingEffects_7, SubLayer.CharacteristicDefining_7a, ability, game); effect.apply(Layer.PTChangingEffects_7, SubLayer.CharacteristicDefining_7a, ability, game);
@ -963,13 +963,13 @@ public class ContinuousEffects implements Serializable {
} }
} }
for (ContinuousEffect effect : layer) { for (ContinuousEffect effect : layer) {
HashSet<Ability> abilities = layeredEffects.getAbility(effect.getId()); Set<Ability> abilities = layeredEffects.getAbility(effect.getId());
for (Ability ability : abilities) { for (Ability ability : abilities) {
effect.apply(Layer.PTChangingEffects_7, SubLayer.SetPT_7b, ability, game); effect.apply(Layer.PTChangingEffects_7, SubLayer.SetPT_7b, ability, game);
} }
} }
for (ContinuousEffect effect : layer) { for (ContinuousEffect effect : layer) {
HashSet<Ability> abilities = layeredEffects.getAbility(effect.getId()); Set<Ability> abilities = layeredEffects.getAbility(effect.getId());
for (Ability ability : abilities) { for (Ability ability : abilities) {
effect.apply(Layer.PTChangingEffects_7, SubLayer.ModifyPT_7c, ability, game); effect.apply(Layer.PTChangingEffects_7, SubLayer.ModifyPT_7c, ability, game);
} }
@ -978,21 +978,21 @@ public class ContinuousEffects implements Serializable {
applyCounters.apply(Layer.PTChangingEffects_7, SubLayer.Counters_7d, null, game); applyCounters.apply(Layer.PTChangingEffects_7, SubLayer.Counters_7d, null, game);
for (ContinuousEffect effect : layer) { for (ContinuousEffect effect : layer) {
HashSet<Ability> abilities = layeredEffects.getAbility(effect.getId()); Set<Ability> abilities = layeredEffects.getAbility(effect.getId());
for (Ability ability : abilities) { for (Ability ability : abilities) {
effect.apply(Layer.PTChangingEffects_7, SubLayer.SwitchPT_e, ability, game); effect.apply(Layer.PTChangingEffects_7, SubLayer.SwitchPT_e, ability, game);
} }
} }
layer = filterLayeredEffects(activeLayerEffects, Layer.PlayerEffects); layer = filterLayeredEffects(activeLayerEffects, Layer.PlayerEffects);
for (ContinuousEffect effect : layer) { for (ContinuousEffect effect : layer) {
HashSet<Ability> abilities = layeredEffects.getAbility(effect.getId()); Set<Ability> abilities = layeredEffects.getAbility(effect.getId());
for (Ability ability : abilities) { for (Ability ability : abilities) {
effect.apply(Layer.PlayerEffects, SubLayer.NA, ability, game); effect.apply(Layer.PlayerEffects, SubLayer.NA, ability, game);
} }
} }
layer = filterLayeredEffects(activeLayerEffects, Layer.RulesEffects); layer = filterLayeredEffects(activeLayerEffects, Layer.RulesEffects);
for (ContinuousEffect effect : layer) { for (ContinuousEffect effect : layer) {
HashSet<Ability> abilities = layeredEffects.getAbility(effect.getId()); Set<Ability> abilities = layeredEffects.getAbility(effect.getId());
for (Ability ability : abilities) { for (Ability ability : abilities) {
effect.apply(Layer.RulesEffects, SubLayer.NA, ability, game); effect.apply(Layer.RulesEffects, SubLayer.NA, ability, game);
} }
@ -1034,13 +1034,13 @@ public class ContinuousEffects implements Serializable {
} }
private void applyContinuousEffect(ContinuousEffect effect, Layer currentLayer, Game game) { private void applyContinuousEffect(ContinuousEffect effect, Layer currentLayer, Game game) {
HashSet<Ability> abilities = layeredEffects.getAbility(effect.getId()); Set<Ability> abilities = layeredEffects.getAbility(effect.getId());
for (Ability ability : abilities) { for (Ability ability : abilities) {
effect.apply(currentLayer, SubLayer.NA, ability, game); effect.apply(currentLayer, SubLayer.NA, ability, game);
} }
} }
public HashSet<Ability> getLayeredEffectAbilities(ContinuousEffect effect) { public Set<Ability> getLayeredEffectAbilities(ContinuousEffect effect) {
return layeredEffects.getAbility(effect.getId()); return layeredEffects.getAbility(effect.getId());
} }
@ -1135,7 +1135,7 @@ public class ContinuousEffects implements Serializable {
private void setControllerForEffect(ContinuousEffectsList<?> effects, UUID sourceId, UUID controllerId) { private void setControllerForEffect(ContinuousEffectsList<?> effects, UUID sourceId, UUID controllerId) {
for (Effect effect : effects) { for (Effect effect : effects) {
HashSet<Ability> abilities = effects.getAbility(effect.getId()); Set<Ability> abilities = effects.getAbility(effect.getId());
for (Ability ability : abilities) { for (Ability ability : abilities) {
if (ability.getSourceId() != null) { if (ability.getSourceId() != null) {
if (ability.getSourceId().equals(sourceId)) { if (ability.getSourceId().equals(sourceId)) {
@ -1200,9 +1200,9 @@ public class ContinuousEffects implements Serializable {
temporaryEffects.clear(); temporaryEffects.clear();
} }
public Map<String, String> getReplacementEffectsTexts(HashMap<ReplacementEffect, HashSet<Ability>> rEffects, Game game) { public Map<String, String> getReplacementEffectsTexts(Map<ReplacementEffect, Set<Ability>> rEffects, Game game) {
Map<String, String> texts = new LinkedHashMap<>(); Map<String, String> texts = new LinkedHashMap<>();
for (Map.Entry<ReplacementEffect, HashSet<Ability>> entry : rEffects.entrySet()) { for (Map.Entry<ReplacementEffect, Set<Ability>> entry : rEffects.entrySet()) {
if (entry.getValue() != null) { if (entry.getValue() != null) {
for (Ability ability : entry.getValue()) { for (Ability ability : entry.getValue()) {
MageObject object = game.getObject(ability.getSourceId()); MageObject object = game.getObject(ability.getSourceId());
@ -1229,7 +1229,7 @@ public class ContinuousEffects implements Serializable {
public UUID getControllerOfSourceId(UUID sourceId) { public UUID getControllerOfSourceId(UUID sourceId) {
UUID controllerFound = null; UUID controllerFound = null;
for (PreventionEffect effect : preventionEffects) { for (PreventionEffect effect : preventionEffects) {
HashSet<Ability> abilities = preventionEffects.getAbility(effect.getId()); Set<Ability> abilities = preventionEffects.getAbility(effect.getId());
for (Ability ability : abilities) { for (Ability ability : abilities) {
if (ability.getSourceId().equals(sourceId)) { if (ability.getSourceId().equals(sourceId)) {
if (controllerFound == null || controllerFound.equals(ability.getControllerId())) { if (controllerFound == null || controllerFound.equals(ability.getControllerId())) {
@ -1242,7 +1242,7 @@ public class ContinuousEffects implements Serializable {
} }
} }
for (ReplacementEffect effect : replacementEffects) { for (ReplacementEffect effect : replacementEffects) {
HashSet<Ability> abilities = replacementEffects.getAbility(effect.getId()); Set<Ability> abilities = replacementEffects.getAbility(effect.getId());
for (Ability ability : abilities) { for (Ability ability : abilities) {
if (ability.getSourceId() != null) { if (ability.getSourceId() != null) {
if (ability.getSourceId().equals(sourceId)) { if (ability.getSourceId().equals(sourceId)) {

View file

@ -27,20 +27,14 @@
*/ */
package mage.abilities.effects; package mage.abilities.effects;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.MageSingleton; import mage.abilities.MageSingleton;
import mage.constants.Duration; import mage.constants.Duration;
import mage.game.Game; import mage.game.Game;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import java.util.*;
/** /**
* @param <T> * @param <T>
* @author BetaSteward_at_googlemail.com * @author BetaSteward_at_googlemail.com
@ -50,7 +44,7 @@ public class ContinuousEffectsList<T extends ContinuousEffect> extends ArrayList
private static final Logger logger = Logger.getLogger(ContinuousEffectsList.class); private static final Logger logger = Logger.getLogger(ContinuousEffectsList.class);
// the effectAbilityMap holds for each effect all abilities that are connected (used) with this effect // the effectAbilityMap holds for each effect all abilities that are connected (used) with this effect
private final Map<UUID, HashSet<Ability>> effectAbilityMap = new HashMap<>(); private final Map<UUID, Set<Ability>> effectAbilityMap = new HashMap<>();
public ContinuousEffectsList() { public ContinuousEffectsList() {
} }
@ -60,8 +54,8 @@ public class ContinuousEffectsList<T extends ContinuousEffect> extends ArrayList
for (ContinuousEffect cost : effects) { for (ContinuousEffect cost : effects) {
this.add((T) cost.copy()); this.add((T) cost.copy());
} }
for (Map.Entry<UUID, HashSet<Ability>> entry : effects.effectAbilityMap.entrySet()) { for (Map.Entry<UUID, Set<Ability>> entry : effects.effectAbilityMap.entrySet()) {
HashSet<Ability> newSet = new HashSet<>(); Set<Ability> newSet = new HashSet<>();
for (Ability ability : entry.getValue()) { for (Ability ability : entry.getValue()) {
newSet.add(ability.copy()); newSet.add(ability.copy());
} }
@ -104,7 +98,7 @@ public class ContinuousEffectsList<T extends ContinuousEffect> extends ArrayList
} }
private boolean isInactive(T effect, Game game) { private boolean isInactive(T effect, Game game) {
HashSet<Ability> set = effectAbilityMap.get(effect.getId()); Set<Ability> set = effectAbilityMap.get(effect.getId());
if (set == null) { if (set == null) {
logger.debug("No abilities for effect found: " + effect.toString()); logger.debug("No abilities for effect found: " + effect.toString());
return false; return false;
@ -153,7 +147,7 @@ public class ContinuousEffectsList<T extends ContinuousEffect> extends ArrayList
*/ */
public void addEffect(T effect, Ability source) { public void addEffect(T effect, Ability source) {
if (effectAbilityMap.containsKey(effect.getId())) { if (effectAbilityMap.containsKey(effect.getId())) {
HashSet<Ability> set = effectAbilityMap.get(effect.getId()); Set<Ability> set = effectAbilityMap.get(effect.getId());
for (Ability ability : set) { for (Ability ability : set) {
if (ability.getId().equals(source.getId()) && ability.getSourceId().equals(source.getSourceId())) { if (ability.getId().equals(source.getId()) && ability.getSourceId().equals(source.getSourceId())) {
return; return;
@ -162,18 +156,18 @@ public class ContinuousEffectsList<T extends ContinuousEffect> extends ArrayList
set.add(source); set.add(source);
return; return;
} }
HashSet<Ability> set = new HashSet<>(); Set<Ability> set = new HashSet<>();
set.add(source); set.add(source);
this.effectAbilityMap.put(effect.getId(), set); this.effectAbilityMap.put(effect.getId(), set);
this.add(effect); this.add(effect);
} }
public HashSet<Ability> getAbility(UUID effectId) { public Set<Ability> getAbility(UUID effectId) {
return effectAbilityMap.getOrDefault(effectId, new HashSet<>()); return effectAbilityMap.getOrDefault(effectId, new HashSet<>());
} }
public void removeEffects(UUID effectIdToRemove, Set<Ability> abilitiesToRemove) { public void removeEffects(UUID effectIdToRemove, Set<Ability> abilitiesToRemove) {
HashSet<Ability> abilities = effectAbilityMap.get(effectIdToRemove); Set<Ability> abilities = effectAbilityMap.get(effectIdToRemove);
if (abilitiesToRemove != null && abilities != null) { if (abilitiesToRemove != null && abilities != null) {
abilities.removeAll(abilitiesToRemove); abilities.removeAll(abilitiesToRemove);
} }

View file

@ -27,8 +27,6 @@
*/ */
package mage.abilities.effects.common; package mage.abilities.effects.common;
import java.util.ArrayList;
import java.util.Arrays;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.choices.Choice; import mage.choices.Choice;
@ -38,13 +36,17 @@ import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/** /**
* *
* @author LevelX2 * @author LevelX2
*/ */
public class ChooseModeEffect extends OneShotEffect { public class ChooseModeEffect extends OneShotEffect {
protected final ArrayList<String> modes = new ArrayList(); protected final List<String> modes = new ArrayList();
protected final String choiceMessage; protected final String choiceMessage;
public ChooseModeEffect(String choiceMessage, String... modes) { public ChooseModeEffect(String choiceMessage, String... modes) {

View file

@ -27,8 +27,6 @@
*/ */
package mage.abilities.effects.common; package mage.abilities.effects.common;
import java.util.ArrayList;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.SpellAbility; import mage.abilities.SpellAbility;
import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.EntersBattlefieldEffect;
@ -39,6 +37,10 @@ import mage.counters.Counter;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/** /**
* Use this effect only (I guess) with EntersBattlefieldAbility like abilities * Use this effect only (I guess) with EntersBattlefieldAbility like abilities
* *
@ -77,7 +79,7 @@ public class EntersBattlefieldWithXCountersEffect extends OneShotEffect {
if (amount > 0) { if (amount > 0) {
Counter counterToAdd = counter.copy(); Counter counterToAdd = counter.copy();
counterToAdd.add(amount - counter.getCount()); counterToAdd.add(amount - counter.getCount());
ArrayList<UUID> appliedEffects = (ArrayList<UUID>) this.getValue("appliedEffects"); List<UUID> appliedEffects = (ArrayList<UUID>) this.getValue("appliedEffects");
permanent.addCounters(counterToAdd, source, game, appliedEffects); permanent.addCounters(counterToAdd, source, game, appliedEffects);
} }
} }

View file

@ -27,7 +27,6 @@
*/ */
package mage.abilities.effects.common.continuous; package mage.abilities.effects.common.continuous;
import java.util.HashSet;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.Mode; import mage.abilities.Mode;
import mage.choices.ChoiceImpl; import mage.choices.ChoiceImpl;
@ -37,6 +36,9 @@ import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import mage.target.Target; import mage.target.Target;
import java.util.HashSet;
import java.util.Set;
/** /**
* *
* @author a * @author a
@ -71,7 +73,7 @@ public class LoseAbilityOrAnotherAbilityTargetEffect extends LoseAbilityTargetEf
ChoiceImpl chooseAbility = new ChoiceImpl(); ChoiceImpl chooseAbility = new ChoiceImpl();
chooseAbility.setMessage("What ability do you wish to remove?"); chooseAbility.setMessage("What ability do you wish to remove?");
HashSet<String> choice = new HashSet<>(); Set<String> choice = new HashSet<>();
if (permanent.getAbilities().contains(ability)) { if (permanent.getAbilities().contains(ability)) {
choice.add(ability.getRule()); choice.add(ability.getRule());

View file

@ -1,8 +1,5 @@
package mage.actions; package mage.actions;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.actions.impl.MageAction; import mage.actions.impl.MageAction;
import mage.actions.score.ArtificialScoringSystem; import mage.actions.score.ArtificialScoringSystem;
import mage.cards.Card; import mage.cards.Card;
@ -12,6 +9,10 @@ import mage.game.events.GameEvent;
import mage.players.Player; import mage.players.Player;
import mage.util.CardUtil; import mage.util.CardUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/** /**
* Action for drawing cards. * Action for drawing cards.
* *
@ -21,12 +22,12 @@ public class MageDrawAction extends MageAction {
private final Player player; private final Player player;
private final int amount; private final int amount;
private final ArrayList<UUID> appliedEffects; private final List<UUID> appliedEffects;
private final List<Card> drawnCards; private final List<Card> drawnCards;
private static final int NEGATIVE_VALUE = -1000000; private static final int NEGATIVE_VALUE = -1000000;
public MageDrawAction(Player player, int amount, ArrayList<UUID> appliedEffects) { public MageDrawAction(Player player, int amount, List<UUID> appliedEffects) {
this.player = player; this.player = player;
this.amount = amount; this.amount = amount;
this.appliedEffects = appliedEffects; this.appliedEffects = appliedEffects;

View file

@ -27,16 +27,12 @@
*/ */
package mage.cards; package mage.cards;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.MageObject; import mage.MageObject;
import mage.Mana; import mage.Mana;
import mage.ObjectColor; import mage.ObjectColor;
import mage.abilities.Abilities; import mage.abilities.Abilities;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.SpellAbility; import mage.abilities.SpellAbility;
import mage.constants.CardType;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.constants.Zone; import mage.constants.Zone;
import mage.counters.Counter; import mage.counters.Counter;
@ -46,6 +42,9 @@ import mage.game.Game;
import mage.game.GameState; import mage.game.GameState;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import java.util.List;
import java.util.UUID;
public interface Card extends MageObject { public interface Card extends MageObject {
@ -127,7 +126,7 @@ public interface Card extends MageObject {
*/ */
boolean moveToZone(Zone zone, UUID sourceId, Game game, boolean flag); boolean moveToZone(Zone zone, UUID sourceId, Game game, boolean flag);
boolean moveToZone(Zone zone, UUID sourceId, Game game, boolean flag, ArrayList<UUID> appliedEffects); boolean moveToZone(Zone zone, UUID sourceId, Game game, boolean flag, List<UUID> appliedEffects);
/** /**
* Moves the card to an exile zone * Moves the card to an exile zone
@ -140,7 +139,7 @@ public interface Card extends MageObject {
*/ */
boolean moveToExile(UUID exileId, String name, UUID sourceId, Game game); boolean moveToExile(UUID exileId, String name, UUID sourceId, Game game);
boolean moveToExile(UUID exileId, String name, UUID sourceId, Game game, ArrayList<UUID> appliedEffects); boolean moveToExile(UUID exileId, String name, UUID sourceId, Game game, List<UUID> appliedEffects);
boolean cast(Game game, Zone fromZone, SpellAbility ability, UUID controllerId); boolean cast(Game game, Zone fromZone, SpellAbility ability, UUID controllerId);
@ -152,7 +151,7 @@ public interface Card extends MageObject {
boolean putOntoBattlefield(Game game, Zone fromZone, UUID sourceId, UUID controllerId, boolean tapped, boolean facedown); boolean putOntoBattlefield(Game game, Zone fromZone, UUID sourceId, UUID controllerId, boolean tapped, boolean facedown);
boolean putOntoBattlefield(Game game, Zone fromZone, UUID sourceId, UUID controllerId, boolean tapped, boolean facedown, ArrayList<UUID> appliedEffects); boolean putOntoBattlefield(Game game, Zone fromZone, UUID sourceId, UUID controllerId, boolean tapped, boolean facedown, List<UUID> appliedEffects);
void setZone(Zone zone, Game game); void setZone(Zone zone, Game game);
@ -170,7 +169,7 @@ public interface Card extends MageObject {
boolean addCounters(Counter counter, Ability source, Game game); boolean addCounters(Counter counter, Ability source, Game game);
boolean addCounters(Counter counter, Ability source, Game game, ArrayList<UUID> appliedEffects); boolean addCounters(Counter counter, Ability source, Game game, List<UUID> appliedEffects);
void removeCounters(String name, int amount, Game game); void removeCounters(String name, int amount, Game game);

View file

@ -28,24 +28,18 @@
package mage.cards; package mage.cards;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.util.*; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import mage.MageObject; import mage.MageObject;
import mage.MageObjectImpl; import mage.MageObjectImpl;
import mage.Mana; import mage.Mana;
import mage.ObjectColor; import mage.ObjectColor;
import mage.abilities.Abilities; import mage.abilities.*;
import mage.abilities.AbilitiesImpl;
import mage.abilities.Ability;
import mage.abilities.PlayLandAbility;
import mage.abilities.SpellAbility;
import mage.abilities.mana.ActivatedManaAbilityImpl; import mage.abilities.mana.ActivatedManaAbilityImpl;
import mage.cards.repository.PluginClassloaderRegistery; import mage.cards.repository.PluginClassloaderRegistery;
import mage.constants.CardType; import mage.constants.*;
import mage.constants.ColoredManaSymbol;
import mage.constants.Rarity;
import mage.constants.SpellAbilityType;
import mage.constants.TimingRule;
import mage.constants.Zone;
import mage.counters.Counter; import mage.counters.Counter;
import mage.counters.Counters; import mage.counters.Counters;
import mage.game.*; import mage.game.*;
@ -286,6 +280,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
/** /**
* Public in order to support adding abilities to SplitCardHalf's * Public in order to support adding abilities to SplitCardHalf's
*
* @param ability * @param ability
*/ */
public void addAbility(Ability ability) { public void addAbility(Ability ability) {
@ -358,7 +353,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
} }
@Override @Override
public boolean moveToZone(Zone toZone, UUID sourceId, Game game, boolean flag, ArrayList<UUID> appliedEffects) { public boolean moveToZone(Zone toZone, UUID sourceId, Game game, boolean flag, List<UUID> appliedEffects) {
Zone fromZone = game.getState().getZone(objectId); Zone fromZone = game.getState().getZone(objectId);
ZoneChangeEvent event = new ZoneChangeEvent(this.objectId, sourceId, ownerId, fromZone, toZone, appliedEffects); ZoneChangeEvent event = new ZoneChangeEvent(this.objectId, sourceId, ownerId, fromZone, toZone, appliedEffects);
ZoneChangeInfo zoneChangeInfo; ZoneChangeInfo zoneChangeInfo;
@ -394,7 +389,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
} }
@Override @Override
public boolean moveToExile(UUID exileId, String name, UUID sourceId, Game game, ArrayList<UUID> appliedEffects) { public boolean moveToExile(UUID exileId, String name, UUID sourceId, Game game, List<UUID> appliedEffects) {
Zone fromZone = game.getState().getZone(objectId); Zone fromZone = game.getState().getZone(objectId);
ZoneChangeEvent event = new ZoneChangeEvent(this.objectId, sourceId, ownerId, fromZone, Zone.EXILED, appliedEffects); ZoneChangeEvent event = new ZoneChangeEvent(this.objectId, sourceId, ownerId, fromZone, Zone.EXILED, appliedEffects);
ZoneChangeInfo.Exile info = new ZoneChangeInfo.Exile(event, exileId, name); ZoneChangeInfo.Exile info = new ZoneChangeInfo.Exile(event, exileId, name);
@ -417,7 +412,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
} }
@Override @Override
public boolean putOntoBattlefield(Game game, Zone fromZone, UUID sourceId, UUID controllerId, boolean tapped, boolean faceDown, ArrayList<UUID> appliedEffects) { public boolean putOntoBattlefield(Game game, Zone fromZone, UUID sourceId, UUID controllerId, boolean tapped, boolean faceDown, List<UUID> appliedEffects) {
ZoneChangeEvent event = new ZoneChangeEvent(this.objectId, sourceId, controllerId, fromZone, Zone.BATTLEFIELD, appliedEffects); ZoneChangeEvent event = new ZoneChangeEvent(this.objectId, sourceId, controllerId, fromZone, Zone.BATTLEFIELD, appliedEffects);
ZoneChangeInfo.Battlefield info = new ZoneChangeInfo.Battlefield(event, faceDown, tapped); ZoneChangeInfo.Battlefield info = new ZoneChangeInfo.Battlefield(event, faceDown, tapped);
return ZonesHandler.moveCard(info, game); return ZonesHandler.moveCard(info, game);
@ -627,9 +622,9 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
} }
@Override @Override
public boolean addCounters(Counter counter, Ability source, Game game, ArrayList<UUID> appliedEffects) { public boolean addCounters(Counter counter, Ability source, Game game, List<UUID> appliedEffects) {
boolean returnCode = true; boolean returnCode = true;
UUID sourceId = (source == null ? null : source.getSourceId()); UUID sourceId = (source == null ? getId() : source.getSourceId());
GameEvent countersEvent = GameEvent.getEvent(GameEvent.EventType.ADD_COUNTERS, objectId, sourceId, getControllerOrOwner(), counter.getName(), counter.getCount()); GameEvent countersEvent = GameEvent.getEvent(GameEvent.EventType.ADD_COUNTERS, objectId, sourceId, getControllerOrOwner(), counter.getName(), counter.getCount());
countersEvent.setAppliedEffects(appliedEffects); countersEvent.setAppliedEffects(appliedEffects);
if (!game.replaceEvent(countersEvent)) { if (!game.replaceEvent(countersEvent)) {

View file

@ -27,8 +27,6 @@
*/ */
package mage.cards; package mage.cards;
import java.util.ArrayList;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Zone; import mage.constants.Zone;
@ -37,6 +35,9 @@ import mage.game.Game;
import mage.game.events.ZoneChangeEvent; import mage.game.events.ZoneChangeEvent;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import java.util.List;
import java.util.UUID;
/** /**
* *
* @author emerald000 * @author emerald000
@ -133,7 +134,7 @@ public abstract class MeldCard extends CardImpl {
} }
@Override @Override
public boolean addCounters(Counter counter, Ability source, Game game, ArrayList<UUID> appliedEffects) { public boolean addCounters(Counter counter, Ability source, Game game, List<UUID> appliedEffects) {
if (this.isMelded()) { if (this.isMelded()) {
return super.addCounters(counter, source, game, appliedEffects); return super.addCounters(counter, source, game, appliedEffects);
} else { } else {

View file

@ -27,9 +27,6 @@
*/ */
package mage.cards; package mage.cards;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.abilities.Abilities; import mage.abilities.Abilities;
import mage.abilities.AbilitiesImpl; import mage.abilities.AbilitiesImpl;
import mage.abilities.Ability; import mage.abilities.Ability;
@ -39,6 +36,10 @@ import mage.constants.SpellAbilityType;
import mage.constants.Zone; import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/** /**
* *
* @author LevelX2 * @author LevelX2
@ -91,7 +92,7 @@ public abstract class SplitCard extends CardImpl {
} }
@Override @Override
public boolean moveToZone(Zone toZone, UUID sourceId, Game game, boolean flag, ArrayList<UUID> appliedEffects) { public boolean moveToZone(Zone toZone, UUID sourceId, Game game, boolean flag, List<UUID> appliedEffects) {
if (super.moveToZone(toZone, sourceId, game, flag, appliedEffects)) { if (super.moveToZone(toZone, sourceId, game, flag, appliedEffects)) {
game.getState().setZone(getLeftHalfCard().getId(), toZone); game.getState().setZone(getLeftHalfCard().getId(), toZone);
game.getState().setZone(getRightHalfCard().getId(), toZone); game.getState().setZone(getRightHalfCard().getId(), toZone);
@ -101,7 +102,7 @@ public abstract class SplitCard extends CardImpl {
} }
@Override @Override
public boolean moveToExile(UUID exileId, String name, UUID sourceId, Game game, ArrayList<UUID> appliedEffects) { public boolean moveToExile(UUID exileId, String name, UUID sourceId, Game game, List<UUID> appliedEffects) {
if (super.moveToExile(exileId, name, sourceId, game, appliedEffects)) { if (super.moveToExile(exileId, name, sourceId, game, appliedEffects)) {
Zone currentZone = game.getState().getZone(getId()); Zone currentZone = game.getState().getZone(getId());
game.getState().setZone(getLeftHalfCard().getId(), currentZone); game.getState().setZone(getLeftHalfCard().getId(), currentZone);

View file

@ -5,13 +5,15 @@
*/ */
package mage.cards; package mage.cards;
import java.util.ArrayList;
import java.util.UUID;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SpellAbilityType; import mage.constants.SpellAbilityType;
import mage.constants.Zone; import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/** /**
* *
* @author LevelX2 * @author LevelX2
@ -51,12 +53,12 @@ public class SplitCardHalfImpl extends CardImpl implements SplitCardHalf {
} }
@Override @Override
public boolean moveToZone(Zone toZone, UUID sourceId, Game game, boolean flag, ArrayList<UUID> appliedEffects) { public boolean moveToZone(Zone toZone, UUID sourceId, Game game, boolean flag, List<UUID> appliedEffects) {
return splitCardParent.moveToZone(toZone, sourceId, game, flag, appliedEffects); return splitCardParent.moveToZone(toZone, sourceId, game, flag, appliedEffects);
} }
@Override @Override
public boolean moveToExile(UUID exileId, String name, UUID sourceId, Game game, ArrayList<UUID> appliedEffects) { public boolean moveToExile(UUID exileId, String name, UUID sourceId, Game game, List<UUID> appliedEffects) {
return splitCardParent.moveToExile(exileId, name, sourceId, game, appliedEffects); return splitCardParent.moveToExile(exileId, name, sourceId, game, appliedEffects);
} }

View file

@ -27,15 +27,6 @@
*/ */
package mage.game.combat; package mage.game.combat;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import mage.MageObject; import mage.MageObject;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.effects.RequirementEffect; import mage.abilities.effects.RequirementEffect;
@ -59,6 +50,9 @@ import mage.util.Copyable;
import mage.util.trace.TraceUtil; import mage.util.trace.TraceUtil;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import java.io.Serializable;
import java.util.*;
/** /**
* @author BetaSteward_at_googlemail.com * @author BetaSteward_at_googlemail.com
*/ */
@ -308,7 +302,7 @@ public class Combat implements Serializable, Copyable<Combat> {
for (Permanent creature : player.getAvailableAttackers(game)) { for (Permanent creature : player.getAvailableAttackers(game)) {
boolean mustAttack = false; boolean mustAttack = false;
Set<UUID> defendersForcedToAttack = new HashSet<>(); Set<UUID> defendersForcedToAttack = new HashSet<>();
for (Map.Entry<RequirementEffect, HashSet<Ability>> entry : game.getContinuousEffects().getApplicableRequirementEffects(creature, game).entrySet()) { for (Map.Entry<RequirementEffect, Set<Ability>> entry : game.getContinuousEffects().getApplicableRequirementEffects(creature, game).entrySet()) {
RequirementEffect effect = entry.getKey(); RequirementEffect effect = entry.getKey();
if (effect.mustAttack(game)) { if (effect.mustAttack(game)) {
mustAttack = true; mustAttack = true;
@ -395,7 +389,7 @@ public class Combat implements Serializable, Copyable<Combat> {
} }
for (UUID attackingCreatureId : this.getAttackers()) { for (UUID attackingCreatureId : this.getAttackers()) {
Permanent attackingCreature = game.getPermanent(attackingCreatureId); Permanent attackingCreature = game.getPermanent(attackingCreatureId);
for (Map.Entry<RestrictionEffect, HashSet<Ability>> entry : game.getContinuousEffects().getApplicableRestrictionEffects(attackingCreature, game).entrySet()) { for (Map.Entry<RestrictionEffect, Set<Ability>> entry : game.getContinuousEffects().getApplicableRestrictionEffects(attackingCreature, game).entrySet()) {
RestrictionEffect effect = entry.getKey(); RestrictionEffect effect = entry.getKey();
for (Ability ability : entry.getValue()) { for (Ability ability : entry.getValue()) {
if (!effect.canAttackCheckAfter(numberAttackers, ability, game)) { if (!effect.canAttackCheckAfter(numberAttackers, ability, game)) {
@ -581,7 +575,7 @@ public class Combat implements Serializable, Copyable<Combat> {
return; return;
} }
for (Permanent possibleBlocker : game.getBattlefield().getActivePermanents(filterBlockers, attackingPlayer.getId(), game)) { for (Permanent possibleBlocker : game.getBattlefield().getActivePermanents(filterBlockers, attackingPlayer.getId(), game)) {
for (Map.Entry<RequirementEffect, HashSet<Ability>> requirementEntry : game.getContinuousEffects().getApplicableRequirementEffects(possibleBlocker, game).entrySet()) { for (Map.Entry<RequirementEffect, Set<Ability>> requirementEntry : game.getContinuousEffects().getApplicableRequirementEffects(possibleBlocker, game).entrySet()) {
if (requirementEntry.getKey().mustBlock(game)) { if (requirementEntry.getKey().mustBlock(game)) {
for (Ability ability : requirementEntry.getValue()) { for (Ability ability : requirementEntry.getValue()) {
UUID attackingCreatureId = requirementEntry.getKey().mustBlockAttacker(ability, game); UUID attackingCreatureId = requirementEntry.getKey().mustBlockAttacker(ability, game);
@ -658,7 +652,7 @@ public class Combat implements Serializable, Copyable<Combat> {
// Creature is already blocking but not forced to do so // Creature is already blocking but not forced to do so
if (creature.getBlocking() > 0) { if (creature.getBlocking() > 0) {
// get all requirement effects that apply to the creature (e.g. is able to block attacker) // get all requirement effects that apply to the creature (e.g. is able to block attacker)
for (Map.Entry<RequirementEffect, HashSet<Ability>> entry : game.getContinuousEffects().getApplicableRequirementEffects(creature, game).entrySet()) { for (Map.Entry<RequirementEffect, Set<Ability>> entry : game.getContinuousEffects().getApplicableRequirementEffects(creature, game).entrySet()) {
RequirementEffect effect = entry.getKey(); RequirementEffect effect = entry.getKey();
// get possible mustBeBlockedByAtLeastOne blocker // get possible mustBeBlockedByAtLeastOne blocker
for (Ability ability : entry.getValue()) { for (Ability ability : entry.getValue()) {
@ -680,7 +674,7 @@ public class Combat implements Serializable, Copyable<Combat> {
// Creature is not blocking yet // Creature is not blocking yet
if (creature.getBlocking() == 0) { if (creature.getBlocking() == 0) {
// get all requirement effects that apply to the creature // get all requirement effects that apply to the creature
for (Map.Entry<RequirementEffect, HashSet<Ability>> entry : game.getContinuousEffects().getApplicableRequirementEffects(creature, game).entrySet()) { for (Map.Entry<RequirementEffect, Set<Ability>> entry : game.getContinuousEffects().getApplicableRequirementEffects(creature, game).entrySet()) {
RequirementEffect effect = entry.getKey(); RequirementEffect effect = entry.getKey();
// get possible mustBeBlockedByAtLeastOne blocker // get possible mustBeBlockedByAtLeastOne blocker
for (Ability ability : entry.getValue()) { for (Ability ability : entry.getValue()) {
@ -980,7 +974,7 @@ public class Combat implements Serializable, Copyable<Combat> {
for (UUID blockingCreatureId : this.getBlockers()) { for (UUID blockingCreatureId : this.getBlockers()) {
Permanent blockingCreature = game.getPermanent(blockingCreatureId); Permanent blockingCreature = game.getPermanent(blockingCreatureId);
if (blockingCreature != null) { if (blockingCreature != null) {
for (Map.Entry<RestrictionEffect, HashSet<Ability>> entry : game.getContinuousEffects().getApplicableRestrictionEffects(blockingCreature, game).entrySet()) { for (Map.Entry<RestrictionEffect, Set<Ability>> entry : game.getContinuousEffects().getApplicableRestrictionEffects(blockingCreature, game).entrySet()) {
RestrictionEffect effect = entry.getKey(); RestrictionEffect effect = entry.getKey();
for (Ability ability : entry.getValue()) { for (Ability ability : entry.getValue()) {
if (!effect.canBlockCheckAfter(ability, game)) { if (!effect.canBlockCheckAfter(ability, game)) {
@ -1000,7 +994,7 @@ public class Combat implements Serializable, Copyable<Combat> {
for (UUID attackingCreatureId : this.getAttackers()) { for (UUID attackingCreatureId : this.getAttackers()) {
Permanent attackingCreature = game.getPermanent(attackingCreatureId); Permanent attackingCreature = game.getPermanent(attackingCreatureId);
if (attackingCreature != null) { if (attackingCreature != null) {
for (Map.Entry<RestrictionEffect, HashSet<Ability>> entry : game.getContinuousEffects().getApplicableRestrictionEffects(attackingCreature, game).entrySet()) { for (Map.Entry<RestrictionEffect, Set<Ability>> entry : game.getContinuousEffects().getApplicableRestrictionEffects(attackingCreature, game).entrySet()) {
RestrictionEffect effect = entry.getKey(); RestrictionEffect effect = entry.getKey();
for (Ability ability : entry.getValue()) { for (Ability ability : entry.getValue()) {
if (!effect.canBeBlockedCheckAfter(attackingCreature, ability, game)) { if (!effect.canBeBlockedCheckAfter(attackingCreature, ability, game)) {

View file

@ -340,7 +340,7 @@ public abstract class DraftImpl implements Draft {
@Override @Override
public void resetBufferedCards() { public void resetBufferedCards() {
HashSet<ExpansionSet> setsDone = new HashSet<>(); Set<ExpansionSet> setsDone = new HashSet<>();
for(ExpansionSet set: sets) { for(ExpansionSet set: sets) {
if (!setsDone.contains(set)) { if (!setsDone.contains(set)) {
set.removeSavedCards(); set.removeSavedCards();

View file

@ -27,10 +27,12 @@
*/ */
package mage.game.events; package mage.game.events;
import mage.constants.Zone;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import java.util.UUID; import java.util.UUID;
import mage.constants.Zone;
/** /**
* *
@ -46,7 +48,7 @@ public class GameEvent implements Serializable {
protected boolean flag; protected boolean flag;
protected String data; protected String data;
protected Zone zone; protected Zone zone;
protected ArrayList<UUID> appliedEffects = new ArrayList<>(); protected List<UUID> appliedEffects = new ArrayList<>();
protected UUID customEventType = null; protected UUID customEventType = null;
public enum EventType { public enum EventType {
@ -460,7 +462,7 @@ public class GameEvent implements Serializable {
* *
* @return * @return
*/ */
public ArrayList<UUID> getAppliedEffects() { public List<UUID> getAppliedEffects() {
return appliedEffects; return appliedEffects;
} }
@ -468,13 +470,13 @@ public class GameEvent implements Serializable {
return type == EventType.CUSTOM_EVENT && this.customEventType.equals(customEventType); return type == EventType.CUSTOM_EVENT && this.customEventType.equals(customEventType);
} }
public void addAppliedEffects(ArrayList<UUID> appliedEffects) { public void addAppliedEffects(List<UUID> appliedEffects) {
if (appliedEffects != null) { if (appliedEffects != null) {
this.appliedEffects.addAll(appliedEffects); this.appliedEffects.addAll(appliedEffects);
} }
} }
public void setAppliedEffects(ArrayList<UUID> appliedEffects) { public void setAppliedEffects(List<UUID> appliedEffects) {
if (appliedEffects != null) { if (appliedEffects != null) {
if (this.appliedEffects.isEmpty()) { if (this.appliedEffects.isEmpty()) {
this.appliedEffects = appliedEffects; // Use object refecence to handle that an replacement effect can only be once applied to an event this.appliedEffects = appliedEffects; // Use object refecence to handle that an replacement effect can only be once applied to an event

View file

@ -28,11 +28,12 @@
package mage.game.events; package mage.game.events;
import java.util.ArrayList;
import java.util.UUID;
import mage.constants.Zone; import mage.constants.Zone;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import java.util.List;
import java.util.UUID;
/** /**
* *
* @author BetaSteward_at_googlemail.com * @author BetaSteward_at_googlemail.com
@ -50,7 +51,7 @@ public class ZoneChangeEvent extends GameEvent {
this.target = target; this.target = target;
} }
public ZoneChangeEvent(Permanent target, UUID sourceId, UUID playerId, Zone fromZone, Zone toZone, ArrayList<UUID> appliedEffects) { public ZoneChangeEvent(Permanent target, UUID sourceId, UUID playerId, Zone fromZone, Zone toZone, List<UUID> appliedEffects) {
super(EventType.ZONE_CHANGE, target.getId(), sourceId, playerId); super(EventType.ZONE_CHANGE, target.getId(), sourceId, playerId);
this.fromZone = fromZone; this.fromZone = fromZone;
this.toZone = toZone; this.toZone = toZone;
@ -66,7 +67,7 @@ public class ZoneChangeEvent extends GameEvent {
this.toZone = toZone; this.toZone = toZone;
} }
public ZoneChangeEvent(UUID targetId, UUID sourceId, UUID playerId, Zone fromZone, Zone toZone, ArrayList<UUID> appliedEffects) { public ZoneChangeEvent(UUID targetId, UUID sourceId, UUID playerId, Zone fromZone, Zone toZone, List<UUID> appliedEffects) {
super(EventType.ZONE_CHANGE, targetId, sourceId, playerId); super(EventType.ZONE_CHANGE, targetId, sourceId, playerId);
this.fromZone = fromZone; this.fromZone = fromZone;
this.toZone = toZone; this.toZone = toZone;

View file

@ -27,10 +27,6 @@
*/ */
package mage.game.permanent; package mage.game.permanent;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.UUID;
import mage.MageObject; import mage.MageObject;
import mage.MageObjectReference; import mage.MageObjectReference;
import mage.abilities.Ability; import mage.abilities.Ability;
@ -41,6 +37,10 @@ import mage.game.Controllable;
import mage.game.Game; import mage.game.Game;
import mage.game.GameState; import mage.game.GameState;
import java.util.List;
import java.util.Set;
import java.util.UUID;
public interface Permanent extends Card, Controllable { public interface Permanent extends Card, Controllable {
void setControllerId(UUID controllerId); void setControllerId(UUID controllerId);
@ -129,7 +129,7 @@ public interface Permanent extends Card, Controllable {
int damage(int damage, UUID sourceId, Game game, boolean combat, boolean preventable); int damage(int damage, UUID sourceId, Game game, boolean combat, boolean preventable);
int damage(int damage, UUID sourceId, Game game, boolean combat, boolean preventable, ArrayList<UUID> appliedEffects); int damage(int damage, UUID sourceId, Game game, boolean combat, boolean preventable, List<UUID> appliedEffects);
/** /**
* used in combat only to deal damage at the same time * used in combat only to deal damage at the same time
@ -267,7 +267,7 @@ public interface Permanent extends Card, Controllable {
* *
* @return * @return
*/ */
HashSet<MageObjectReference> getDealtDamageByThisTurn(); Set<MageObjectReference> getDealtDamageByThisTurn();
/** /**
* Imprint some other card to this one. * Imprint some other card to this one.

View file

@ -27,7 +27,6 @@
*/ */
package mage.game.permanent; package mage.game.permanent;
import java.util.*;
import mage.MageObject; import mage.MageObject;
import mage.MageObjectReference; import mage.MageObjectReference;
import mage.ObjectColor; import mage.ObjectColor;
@ -56,6 +55,8 @@ import mage.players.Player;
import mage.util.GameLog; import mage.util.GameLog;
import mage.util.ThreadLocalStringBuilder; import mage.util.ThreadLocalStringBuilder;
import java.util.*;
/** /**
* @author BetaSteward_at_googlemail.com * @author BetaSteward_at_googlemail.com
*/ */
@ -100,7 +101,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
protected boolean deathtouched; protected boolean deathtouched;
protected List<UUID> attachments = new ArrayList<>(); protected List<UUID> attachments = new ArrayList<>();
protected Map<String, List<UUID>> connectedCards = new HashMap<>(); protected Map<String, List<UUID>> connectedCards = new HashMap<>();
protected HashSet<MageObjectReference> dealtDamageByThisTurn; protected Set<MageObjectReference> dealtDamageByThisTurn;
protected UUID attachedTo; protected UUID attachedTo;
protected int attachedToZoneChangeCounter; protected int attachedToZoneChangeCounter;
protected MageObjectReference pairedPermanent; protected MageObjectReference pairedPermanent;
@ -695,7 +696,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
} }
@Override @Override
public int damage(int damage, UUID sourceId, Game game, boolean combat, boolean preventable, ArrayList<UUID> appliedEffects) { public int damage(int damage, UUID sourceId, Game game, boolean combat, boolean preventable, List<UUID> appliedEffects) {
return damage(damage, sourceId, game, preventable, combat, false, appliedEffects); return damage(damage, sourceId, game, preventable, combat, false, appliedEffects);
} }
@ -709,7 +710,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
* method * method
* @return * @return
*/ */
private int damage(int damageAmount, UUID sourceId, Game game, boolean preventable, boolean combat, boolean markDamage, ArrayList<UUID> appliedEffects) { private int damage(int damageAmount, UUID sourceId, Game game, boolean preventable, boolean combat, boolean markDamage, List<UUID> appliedEffects) {
int damageDone = 0; int damageDone = 0;
if (damageAmount > 0 && canDamage(game.getObject(sourceId), game)) { if (damageAmount > 0 && canDamage(game.getObject(sourceId), game)) {
if (this.isPlaneswalker()) { if (this.isPlaneswalker()) {
@ -794,7 +795,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
deathtouched = false; deathtouched = false;
} }
protected int damagePlaneswalker(int damage, UUID sourceId, Game game, boolean preventable, boolean combat, boolean markDamage, ArrayList<UUID> appliedEffects) { protected int damagePlaneswalker(int damage, UUID sourceId, Game game, boolean preventable, boolean combat, boolean markDamage, List<UUID> appliedEffects) {
GameEvent event = new DamagePlaneswalkerEvent(objectId, sourceId, controllerId, damage, preventable, combat); GameEvent event = new DamagePlaneswalkerEvent(objectId, sourceId, controllerId, damage, preventable, combat);
event.setAppliedEffects(appliedEffects); event.setAppliedEffects(appliedEffects);
if (!game.replaceEvent(event)) { if (!game.replaceEvent(event)) {
@ -812,7 +813,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
return 0; return 0;
} }
protected int damageCreature(int damage, UUID sourceId, Game game, boolean preventable, boolean combat, boolean markDamage, ArrayList<UUID> appliedEffects) { protected int damageCreature(int damage, UUID sourceId, Game game, boolean preventable, boolean combat, boolean markDamage, List<UUID> appliedEffects) {
GameEvent event = new DamageCreatureEvent(objectId, sourceId, controllerId, damage, preventable, combat); GameEvent event = new DamageCreatureEvent(objectId, sourceId, controllerId, damage, preventable, combat);
event.setAppliedEffects(appliedEffects); event.setAppliedEffects(appliedEffects);
if (!game.replaceEvent(event)) { if (!game.replaceEvent(event)) {
@ -1062,7 +1063,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
private boolean canAttackCheckRestrictionEffects(UUID defenderId, Game game) { private boolean canAttackCheckRestrictionEffects(UUID defenderId, Game game) {
//20101001 - 508.1c //20101001 - 508.1c
for (Map.Entry<RestrictionEffect, HashSet<Ability>> effectEntry : game.getContinuousEffects().getApplicableRestrictionEffects(this, game).entrySet()) { for (Map.Entry<RestrictionEffect, Set<Ability>> effectEntry : game.getContinuousEffects().getApplicableRestrictionEffects(this, game).entrySet()) {
if (!effectEntry.getKey().canAttack(game)) { if (!effectEntry.getKey().canAttack(game)) {
return false; return false;
} }
@ -1090,7 +1091,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
} }
//20101001 - 509.1b //20101001 - 509.1b
// check blocker restrictions // check blocker restrictions
for (Map.Entry<RestrictionEffect, HashSet<Ability>> entry : game.getContinuousEffects().getApplicableRestrictionEffects(this, game).entrySet()) { for (Map.Entry<RestrictionEffect, Set<Ability>> entry : game.getContinuousEffects().getApplicableRestrictionEffects(this, game).entrySet()) {
for (Ability ability : entry.getValue()) { for (Ability ability : entry.getValue()) {
if (!entry.getKey().canBlock(attacker, this, ability, game)) { if (!entry.getKey().canBlock(attacker, this, ability, game)) {
return false; return false;
@ -1098,7 +1099,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
} }
} }
// check also attacker's restriction effects // check also attacker's restriction effects
for (Map.Entry<RestrictionEffect, HashSet<Ability>> restrictionEntry : game.getContinuousEffects().getApplicableRestrictionEffects(attacker, game).entrySet()) { for (Map.Entry<RestrictionEffect, Set<Ability>> restrictionEntry : game.getContinuousEffects().getApplicableRestrictionEffects(attacker, game).entrySet()) {
for (Ability ability : restrictionEntry.getValue()) { for (Ability ability : restrictionEntry.getValue()) {
if (!restrictionEntry.getKey().canBeBlocked(attacker, this, ability, game)) { if (!restrictionEntry.getKey().canBeBlocked(attacker, this, ability, game)) {
return false; return false;
@ -1115,7 +1116,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
} }
//20101001 - 509.1b //20101001 - 509.1b
for (Map.Entry<RestrictionEffect, HashSet<Ability>> entry : game.getContinuousEffects().getApplicableRestrictionEffects(this, game).entrySet()) { for (Map.Entry<RestrictionEffect, Set<Ability>> entry : game.getContinuousEffects().getApplicableRestrictionEffects(this, game).entrySet()) {
RestrictionEffect effect = entry.getKey(); RestrictionEffect effect = entry.getKey();
for (Ability ability : entry.getValue()) { for (Ability ability : entry.getValue()) {
if (!effect.canBlock(null, this, ability, game)) { if (!effect.canBlock(null, this, ability, game)) {
@ -1136,7 +1137,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
*/ */
@Override @Override
public boolean canUseActivatedAbilities(Game game) { public boolean canUseActivatedAbilities(Game game) {
for (Map.Entry<RestrictionEffect, HashSet<Ability>> entry : game.getContinuousEffects().getApplicableRestrictionEffects(this, game).entrySet()) { for (Map.Entry<RestrictionEffect, Set<Ability>> entry : game.getContinuousEffects().getApplicableRestrictionEffects(this, game).entrySet()) {
RestrictionEffect effect = entry.getKey(); RestrictionEffect effect = entry.getKey();
for (Ability ability : entry.getValue()) { for (Ability ability : entry.getValue()) {
if (!effect.canUseActivatedAbilities(this, ability, game)) { if (!effect.canUseActivatedAbilities(this, ability, game)) {
@ -1150,7 +1151,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
@Override @Override
public boolean canTransform(Ability source, Game game) { public boolean canTransform(Ability source, Game game) {
if (transformable) { if (transformable) {
for (Map.Entry<RestrictionEffect, HashSet<Ability>> entry : game.getContinuousEffects().getApplicableRestrictionEffects(this, game).entrySet()) { for (Map.Entry<RestrictionEffect, Set<Ability>> entry : game.getContinuousEffects().getApplicableRestrictionEffects(this, game).entrySet()) {
RestrictionEffect effect = entry.getKey(); RestrictionEffect effect = entry.getKey();
for (Ability ability : entry.getValue()) { for (Ability ability : entry.getValue()) {
if (!effect.canTransform(this, ability, game)) { if (!effect.canTransform(this, ability, game)) {
@ -1237,7 +1238,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
} }
@Override @Override
public HashSet<MageObjectReference> getDealtDamageByThisTurn() { public Set<MageObjectReference> getDealtDamageByThisTurn() {
if (dealtDamageByThisTurn == null) { if (dealtDamageByThisTurn == null) {
return new HashSet<>(); return new HashSet<>();
} }
@ -1376,7 +1377,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
} }
@Override @Override
public boolean moveToZone(Zone toZone, UUID sourceId, Game game, boolean flag, ArrayList<UUID> appliedEffects) { public boolean moveToZone(Zone toZone, UUID sourceId, Game game, boolean flag, List<UUID> appliedEffects) {
Zone fromZone = game.getState().getZone(objectId); Zone fromZone = game.getState().getZone(objectId);
Player controller = game.getPlayer(controllerId); Player controller = game.getPlayer(controllerId);
if (controller != null) { if (controller != null) {
@ -1393,7 +1394,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
} }
@Override @Override
public boolean moveToExile(UUID exileId, String name, UUID sourceId, Game game, ArrayList<UUID> appliedEffects) { public boolean moveToExile(UUID exileId, String name, UUID sourceId, Game game, List<UUID> appliedEffects) {
Zone fromZone = game.getState().getZone(objectId); Zone fromZone = game.getState().getZone(objectId);
ZoneChangeEvent event = new ZoneChangeEvent(this, sourceId, ownerId, fromZone, Zone.EXILED, appliedEffects); ZoneChangeEvent event = new ZoneChangeEvent(this, sourceId, ownerId, fromZone, Zone.EXILED, appliedEffects);
ZoneChangeInfo.Exile info = new ZoneChangeInfo.Exile(event, exileId, name); ZoneChangeInfo.Exile info = new ZoneChangeInfo.Exile(event, exileId, name);

View file

@ -27,10 +27,6 @@
*/ */
package mage.game.stack; package mage.game.stack;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.MageObject; import mage.MageObject;
import mage.Mana; import mage.Mana;
@ -62,6 +58,11 @@ import mage.game.permanent.PermanentCard;
import mage.players.Player; import mage.players.Player;
import mage.util.GameLog; import mage.util.GameLog;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.UUID;
/** /**
* *
* @author BetaSteward_at_googlemail.com * @author BetaSteward_at_googlemail.com
@ -732,7 +733,7 @@ public class Spell extends StackObjImpl implements Card {
} }
@Override @Override
public boolean moveToZone(Zone zone, UUID sourceId, Game game, boolean flag, ArrayList<UUID> appliedEffects) { public boolean moveToZone(Zone zone, UUID sourceId, Game game, boolean flag, List<UUID> appliedEffects) {
// 706.10a If a copy of a spell is in a zone other than the stack, it ceases to exist. // 706.10a If a copy of a spell is in a zone other than the stack, it ceases to exist.
// If a copy of a card is in any zone other than the stack or the battlefield, it ceases to exist. // If a copy of a card is in any zone other than the stack or the battlefield, it ceases to exist.
// These are state-based actions. See rule 704. // These are state-based actions. See rule 704.
@ -748,7 +749,7 @@ public class Spell extends StackObjImpl implements Card {
} }
@Override @Override
public boolean moveToExile(UUID exileId, String name, UUID sourceId, Game game, ArrayList<UUID> appliedEffects) { public boolean moveToExile(UUID exileId, String name, UUID sourceId, Game game, List<UUID> appliedEffects) {
return this.card.moveToExile(exileId, name, sourceId, game, appliedEffects); return this.card.moveToExile(exileId, name, sourceId, game, appliedEffects);
} }
@ -768,7 +769,7 @@ public class Spell extends StackObjImpl implements Card {
} }
@Override @Override
public boolean putOntoBattlefield(Game game, Zone fromZone, UUID sourceId, UUID controllerId, boolean tapped, boolean facedown, ArrayList<UUID> appliedEffects) { public boolean putOntoBattlefield(Game game, Zone fromZone, UUID sourceId, UUID controllerId, boolean tapped, boolean facedown, List<UUID> appliedEffects) {
throw new UnsupportedOperationException("Not supported yet."); throw new UnsupportedOperationException("Not supported yet.");
} }
@ -865,7 +866,7 @@ public class Spell extends StackObjImpl implements Card {
} }
@Override @Override
public boolean addCounters(Counter counter, Ability source, Game game, ArrayList<UUID> appliedEffects) { public boolean addCounters(Counter counter, Ability source, Game game, List<UUID> appliedEffects) {
return card.addCounters(counter, source, game, appliedEffects); return card.addCounters(counter, source, game, appliedEffects);
} }

View file

@ -124,7 +124,7 @@ public interface Player extends MageItem, Copyable<Player> {
int damage(int damage, UUID sourceId, Game game, boolean combatDamage, boolean preventable); int damage(int damage, UUID sourceId, Game game, boolean combatDamage, boolean preventable);
int damage(int damage, UUID sourceId, Game game, boolean combatDamage, boolean preventable, ArrayList<UUID> appliedEffects); int damage(int damage, UUID sourceId, Game game, boolean combatDamage, boolean preventable, List<UUID> appliedEffects);
// to handle rule changing effects (613.10) // to handle rule changing effects (613.10)
boolean isCanLoseLife(); boolean isCanLoseLife();
@ -350,7 +350,7 @@ public interface Player extends MageItem, Copyable<Player> {
int drawCards(int num, Game game); int drawCards(int num, Game game);
int drawCards(int num, Game game, ArrayList<UUID> appliedEffects); int drawCards(int num, Game game, List<UUID> appliedEffects);
boolean cast(SpellAbility ability, Game game, boolean noMana); boolean cast(SpellAbility ability, Game game, boolean noMana);
@ -674,7 +674,7 @@ public interface Player extends MageItem, Copyable<Player> {
boolean moveCards(Card card, Zone toZone, Ability source, Game game); boolean moveCards(Card card, Zone toZone, Ability source, Game game);
boolean moveCards(Card card, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, ArrayList<UUID> appliedEffects); boolean moveCards(Card card, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, List<UUID> appliedEffects);
boolean moveCards(Set<Card> cards, Zone toZone, Ability source, Game game); boolean moveCards(Set<Card> cards, Zone toZone, Ability source, Game game);
@ -694,7 +694,7 @@ public interface Player extends MageItem, Copyable<Player> {
* @param appliedEffects * @param appliedEffects
* @return * @return
*/ */
boolean moveCards(Set<Card> cards, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, ArrayList<UUID> appliedEffects); boolean moveCards(Set<Card> cards, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, List<UUID> appliedEffects);
boolean moveCardsToExile(Card card, Ability source, Game game, boolean withName, UUID exileId, String exileZoneName); boolean moveCardsToExile(Card card, Ability source, Game game, boolean withName, UUID exileId, String exileZoneName);

View file

@ -27,10 +27,6 @@
*/ */
package mage.players; package mage.players;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.Map.Entry;
import mage.ConditionalMana; import mage.ConditionalMana;
import mage.MageObject; import mage.MageObject;
import mage.Mana; import mage.Mana;
@ -91,6 +87,11 @@ import mage.util.GameLog;
import mage.util.RandomUtil; import mage.util.RandomUtil;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.Map.Entry;
public abstract class PlayerImpl implements Player, Serializable { public abstract class PlayerImpl implements Player, Serializable {
private static final Logger logger = Logger.getLogger(PlayerImpl.class); private static final Logger logger = Logger.getLogger(PlayerImpl.class);
@ -621,7 +622,7 @@ public abstract class PlayerImpl implements Player, Serializable {
} }
@Override @Override
public int drawCards(int num, Game game, ArrayList<UUID> appliedEffects) { public int drawCards(int num, Game game, List<UUID> appliedEffects) {
return game.doAction(new MageDrawAction(this, num, appliedEffects)); return game.doAction(new MageDrawAction(this, num, appliedEffects));
} }
@ -1472,8 +1473,8 @@ public abstract class PlayerImpl implements Player, Serializable {
@Override @Override
public void untap(Game game) { public void untap(Game game) {
// create list of all "notMoreThan" effects to track which one are consumed // create list of all "notMoreThan" effects to track which one are consumed
HashMap<Entry<RestrictionUntapNotMoreThanEffect, HashSet<Ability>>, Integer> notMoreThanEffectsUsage = new HashMap<>(); HashMap<Entry<RestrictionUntapNotMoreThanEffect, Set<Ability>>, Integer> notMoreThanEffectsUsage = new HashMap<>();
for (Entry<RestrictionUntapNotMoreThanEffect, HashSet<Ability>> restrictionEffect : game.getContinuousEffects().getApplicableRestrictionUntapNotMoreThanEffects(this, game).entrySet()) { for (Entry<RestrictionUntapNotMoreThanEffect, Set<Ability>> restrictionEffect : game.getContinuousEffects().getApplicableRestrictionUntapNotMoreThanEffects(this, game).entrySet()) {
notMoreThanEffectsUsage.put(restrictionEffect, restrictionEffect.getKey().getNumber()); notMoreThanEffectsUsage.put(restrictionEffect, restrictionEffect.getKey().getNumber());
} }
@ -1497,7 +1498,7 @@ public abstract class PlayerImpl implements Player, Serializable {
do { do {
playerCanceledSelection = false; playerCanceledSelection = false;
// select permanents to untap to consume the "notMoreThan" effects // select permanents to untap to consume the "notMoreThan" effects
for (Map.Entry<Entry<RestrictionUntapNotMoreThanEffect, HashSet<Ability>>, Integer> handledEntry : notMoreThanEffectsUsage.entrySet()) { for (Map.Entry<Entry<RestrictionUntapNotMoreThanEffect, Set<Ability>>, Integer> handledEntry : notMoreThanEffectsUsage.entrySet()) {
// select a permanent to untap for this entry // select a permanent to untap for this entry
int numberToUntap = handledEntry.getValue(); int numberToUntap = handledEntry.getValue();
if (numberToUntap > 0) { if (numberToUntap > 0) {
@ -1535,7 +1536,7 @@ public abstract class PlayerImpl implements Player, Serializable {
// don't allow to select same permanent twice // don't allow to select same permanent twice
filter.add(Predicates.not(new PermanentIdPredicate(selectedPermanent.getId()))); filter.add(Predicates.not(new PermanentIdPredicate(selectedPermanent.getId())));
// reduce available untap numbers from other "UntapNotMoreThan" effects if selected permanent applies to their filter too // reduce available untap numbers from other "UntapNotMoreThan" effects if selected permanent applies to their filter too
for (Entry<Entry<RestrictionUntapNotMoreThanEffect, HashSet<Ability>>, Integer> notMoreThanEffect : notMoreThanEffectsUsage.entrySet()) { for (Entry<Entry<RestrictionUntapNotMoreThanEffect, Set<Ability>>, Integer> notMoreThanEffect : notMoreThanEffectsUsage.entrySet()) {
if (notMoreThanEffect.getValue() > 0 && notMoreThanEffect.getKey().getKey().getFilter().match(selectedPermanent, game)) { if (notMoreThanEffect.getValue() > 0 && notMoreThanEffect.getKey().getKey().getFilter().match(selectedPermanent, game)) {
notMoreThanEffect.setValue(notMoreThanEffect.getValue() - 1); notMoreThanEffect.setValue(notMoreThanEffect.getValue() - 1);
} }
@ -1574,7 +1575,7 @@ public abstract class PlayerImpl implements Player, Serializable {
boolean doUntap = true; boolean doUntap = true;
if (!selectedToUntap.contains(permanent)) { if (!selectedToUntap.contains(permanent)) {
// if the permanent is covered by one of the restriction effects, don't untap it // if the permanent is covered by one of the restriction effects, don't untap it
for (Entry<Entry<RestrictionUntapNotMoreThanEffect, HashSet<Ability>>, Integer> notMoreThanEffect : notMoreThanEffectsUsage.entrySet()) { for (Entry<Entry<RestrictionUntapNotMoreThanEffect, Set<Ability>>, Integer> notMoreThanEffect : notMoreThanEffectsUsage.entrySet()) {
if (notMoreThanEffect.getKey().getKey().getFilter().match(permanent, game)) { if (notMoreThanEffect.getKey().getKey().getFilter().match(permanent, game)) {
doUntap = false; doUntap = false;
break; break;
@ -1601,14 +1602,14 @@ public abstract class PlayerImpl implements Player, Serializable {
} }
} }
private List<Permanent> getPermanentsThatCanBeUntapped(Game game, List<Permanent> canBeUntapped, RestrictionUntapNotMoreThanEffect handledEffect, HashMap<Entry<RestrictionUntapNotMoreThanEffect, HashSet<Ability>>, Integer> notMoreThanEffectsUsage) { private List<Permanent> getPermanentsThatCanBeUntapped(Game game, List<Permanent> canBeUntapped, RestrictionUntapNotMoreThanEffect handledEffect, Map<Entry<RestrictionUntapNotMoreThanEffect, Set<Ability>>, Integer> notMoreThanEffectsUsage) {
List<Permanent> leftForUntap = new ArrayList<>(); List<Permanent> leftForUntap = new ArrayList<>();
// select permanents that can still be untapped // select permanents that can still be untapped
for (Permanent permanent : canBeUntapped) { for (Permanent permanent : canBeUntapped) {
if (handledEffect.getFilter().match(permanent, game)) { // matches the restricted permanents of handled entry if (handledEffect.getFilter().match(permanent, game)) { // matches the restricted permanents of handled entry
boolean canBeSelected = true; boolean canBeSelected = true;
// check if the permanent is restriced by another restriction that has left no permanent // check if the permanent is restriced by another restriction that has left no permanent
for (Entry<Entry<RestrictionUntapNotMoreThanEffect, HashSet<Ability>>, Integer> notMoreThanEffect : notMoreThanEffectsUsage.entrySet()) { for (Entry<Entry<RestrictionUntapNotMoreThanEffect, Set<Ability>>, Integer> notMoreThanEffect : notMoreThanEffectsUsage.entrySet()) {
if (notMoreThanEffect.getKey().getKey().getFilter().match(permanent, game) && notMoreThanEffect.getValue() == 0) { if (notMoreThanEffect.getKey().getKey().getFilter().match(permanent, game) && notMoreThanEffect.getValue() == 0) {
canBeSelected = false; canBeSelected = false;
break; break;
@ -1763,12 +1764,12 @@ public abstract class PlayerImpl implements Player, Serializable {
} }
@Override @Override
public int damage(int damage, UUID sourceId, Game game, boolean combatDamage, boolean preventable, ArrayList<UUID> appliedEffects) { public int damage(int damage, UUID sourceId, Game game, boolean combatDamage, boolean preventable, List<UUID> appliedEffects) {
return doDamage(damage, sourceId, game, combatDamage, preventable, appliedEffects); return doDamage(damage, sourceId, game, combatDamage, preventable, appliedEffects);
} }
@SuppressWarnings({"null", "ConstantConditions"}) @SuppressWarnings({"null", "ConstantConditions"})
private int doDamage(int damage, UUID sourceId, Game game, boolean combatDamage, boolean preventable, ArrayList<UUID> appliedEffects) { private int doDamage(int damage, UUID sourceId, Game game, boolean combatDamage, boolean preventable, List<UUID> appliedEffects) {
if (damage > 0 && canDamage(game.getObject(sourceId), game)) { if (damage > 0 && canDamage(game.getObject(sourceId), game)) {
GameEvent event = new DamagePlayerEvent(playerId, sourceId, playerId, damage, preventable, combatDamage); GameEvent event = new DamagePlayerEvent(playerId, sourceId, playerId, damage, preventable, combatDamage);
event.setAppliedEffects(appliedEffects); event.setAppliedEffects(appliedEffects);
@ -3093,7 +3094,7 @@ public abstract class PlayerImpl implements Player, Serializable {
} }
@Override @Override
public boolean moveCards(Card card, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, ArrayList<UUID> appliedEffects) { public boolean moveCards(Card card, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, List<UUID> appliedEffects) {
Set<Card> cardList = new HashSet<>(); Set<Card> cardList = new HashSet<>();
if (card != null) { if (card != null) {
cardList.add(card); cardList.add(card);
@ -3112,7 +3113,7 @@ public abstract class PlayerImpl implements Player, Serializable {
} }
@Override @Override
public boolean moveCards(Set<Card> cards, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, ArrayList<UUID> appliedEffects) { public boolean moveCards(Set<Card> cards, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, List<UUID> appliedEffects) {
if (cards.isEmpty()) { if (cards.isEmpty()) {
return true; return true;
} }

View file

@ -1,16 +1,14 @@
package mage.util.trace; package mage.util.trace;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import mage.MageObject; import mage.MageObject;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.StaticAbility; import mage.abilities.StaticAbility;
import mage.abilities.effects.ContinuousEffectsList; import mage.abilities.effects.ContinuousEffectsList;
import mage.abilities.effects.RestrictionEffect; import mage.abilities.effects.RestrictionEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.ReachAbility;
import mage.abilities.keyword.CantBeBlockedSourceAbility; import mage.abilities.keyword.CantBeBlockedSourceAbility;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.IntimidateAbility;
import mage.abilities.keyword.ReachAbility;
import mage.constants.Zone; import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
import mage.game.combat.Combat; import mage.game.combat.Combat;
@ -18,9 +16,7 @@ import mage.game.combat.CombatGroup;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import java.util.UUID; import java.util.*;
import mage.abilities.keyword.IntimidateAbility;
import mage.constants.CardType;
/** /**
* @author magenoxx_at_gmail.com * @author magenoxx_at_gmail.com
@ -146,8 +142,8 @@ public final class TraceUtil {
log.error(prefix+"Restriction effects:"); log.error(prefix+"Restriction effects:");
log.error(prefix+" Applied to ATTACKER:"); log.error(prefix+" Applied to ATTACKER:");
HashMap<RestrictionEffect, HashSet<Ability>> attackerResEffects = game.getContinuousEffects().getApplicableRestrictionEffects(attacker, game); Map<RestrictionEffect, Set<Ability>> attackerResEffects = game.getContinuousEffects().getApplicableRestrictionEffects(attacker, game);
for (Map.Entry<RestrictionEffect, HashSet<Ability>> entry : attackerResEffects.entrySet()) { for (Map.Entry<RestrictionEffect, Set<Ability>> entry : attackerResEffects.entrySet()) {
log.error(prefix+" " + entry.getKey()); log.error(prefix+" " + entry.getKey());
log.error(prefix+" id=" + entry.getKey().getId()); log.error(prefix+" id=" + entry.getKey().getId());
for (Ability ability: entry.getValue()) { for (Ability ability: entry.getValue()) {
@ -156,8 +152,8 @@ public final class TraceUtil {
} }
log.error(prefix+" Applied to BLOCKER:"); log.error(prefix+" Applied to BLOCKER:");
if (blocker != null) { if (blocker != null) {
HashMap<RestrictionEffect, HashSet<Ability>> blockerResEffects = game.getContinuousEffects().getApplicableRestrictionEffects(blocker, game); Map<RestrictionEffect, Set<Ability>> blockerResEffects = game.getContinuousEffects().getApplicableRestrictionEffects(blocker, game);
for (Map.Entry<RestrictionEffect, HashSet<Ability>> entry : blockerResEffects.entrySet()) { for (Map.Entry<RestrictionEffect, Set<Ability>> entry : blockerResEffects.entrySet()) {
log.error(prefix+" " + entry.getKey()); log.error(prefix+" " + entry.getKey());
log.error(prefix+" id=" + entry.getKey().getId()); log.error(prefix+" id=" + entry.getKey().getId());
for (Ability ability: entry.getValue()) { for (Ability ability: entry.getValue()) {

View file

@ -15,8 +15,8 @@ import mage.watchers.Watcher;
*/ */
public class LandfallWatcher extends Watcher { public class LandfallWatcher extends Watcher {
final Set<UUID> playerPlayedLand = new HashSet<>(); // player that played land final Set<UUID> playerPlayedLand = new HashSet<>(); // player that had a land enter the battlefield
final Set<UUID> landPlayed = new HashSet<>(); // land played final Set<UUID> landEnteredBattlefield = new HashSet<>(); // land played
public LandfallWatcher() { public LandfallWatcher() {
super(LandfallWatcher.class.getSimpleName(), WatcherScope.GAME); super(LandfallWatcher.class.getSimpleName(), WatcherScope.GAME);
@ -25,7 +25,7 @@ public class LandfallWatcher extends Watcher {
public LandfallWatcher(final LandfallWatcher watcher) { public LandfallWatcher(final LandfallWatcher watcher) {
super(watcher); super(watcher);
playerPlayedLand.addAll(watcher.playerPlayedLand); playerPlayedLand.addAll(watcher.playerPlayedLand);
landPlayed.addAll(watcher.landPlayed); landEnteredBattlefield.addAll(watcher.landEnteredBattlefield);
} }
@Override @Override
@ -35,13 +35,13 @@ public class LandfallWatcher extends Watcher {
@Override @Override
public void watch(GameEvent event, Game game) { public void watch(GameEvent event, Game game) {
if (event.getType() == GameEvent.EventType.LAND_PLAYED) { if (event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD) {
Permanent permanent = game.getPermanentOrLKIBattlefield(event.getTargetId()); Permanent permanent = game.getPermanentOrLKIBattlefield(event.getTargetId());
if (permanent != null if (permanent != null
&& permanent.isLand() && permanent.isLand()
&& !playerPlayedLand.contains(event.getPlayerId())) { && !playerPlayedLand.contains(event.getPlayerId())) {
playerPlayedLand.add(event.getPlayerId()); playerPlayedLand.add(event.getPlayerId());
landPlayed.add(event.getTargetId()); landEnteredBattlefield.add(event.getTargetId());
} }
} }
} }
@ -49,7 +49,7 @@ public class LandfallWatcher extends Watcher {
@Override @Override
public void reset() { public void reset() {
playerPlayedLand.clear(); playerPlayedLand.clear();
landPlayed.clear(); landEnteredBattlefield.clear();
super.reset(); super.reset();
} }
@ -57,7 +57,7 @@ public class LandfallWatcher extends Watcher {
return playerPlayedLand.contains(playerId); return playerPlayedLand.contains(playerId);
} }
public boolean wasLandPlayed(UUID landId) { public boolean landEnteredBattlefield(UUID landId) {
return landPlayed.contains(landId); return landEnteredBattlefield.contains(landId);
} }
} }

View file

@ -0,0 +1,62 @@
package mage.watchers.common;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import mage.constants.WatcherScope;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.watchers.Watcher;
/**
* @author jeffwadsworth
*/
public class PlayLandWatcher extends Watcher {
final Set<UUID> playerPlayedLand = new HashSet<>(); // player that played land
final Set<UUID> landPlayed = new HashSet<>(); // land played
public PlayLandWatcher() {
super(PlayLandWatcher.class.getSimpleName(), WatcherScope.GAME);
}
public PlayLandWatcher(final PlayLandWatcher watcher) {
super(watcher);
playerPlayedLand.addAll(watcher.playerPlayedLand);
landPlayed.addAll(watcher.landPlayed);
}
@Override
public PlayLandWatcher copy() {
return new PlayLandWatcher(this);
}
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() == GameEvent.EventType.LAND_PLAYED) {
Permanent permanent = game.getPermanentOrLKIBattlefield(event.getTargetId());
if (permanent != null
&& permanent.isLand()
&& !playerPlayedLand.contains(event.getPlayerId())) {
playerPlayedLand.add(event.getPlayerId());
landPlayed.add(event.getTargetId());
}
}
}
@Override
public void reset() {
playerPlayedLand.clear();
landPlayed.clear();
super.reset();
}
public boolean landPlayed(UUID playerId) {
return playerPlayedLand.contains(playerId);
}
public boolean wasLandPlayed(UUID landId) {
return landPlayed.contains(landId);
}
}

View file

@ -0,0 +1,215 @@
#!/usr/bin/perl -w
#author: North
use Text::Template;
use strict;
my $dataFile = "mtg-cards-data.txt";
my $setsFile = "mtg-sets-data.txt";
my $knownSetsFile = "known-sets.txt";
my %cards;
my %sets;
my %knownSets;
my @setCards;
# gets the set name
my $setName = $ARGV[0];
if(!$setName) {
print 'Enter a set name: ';
$setName = <STDIN>;
chomp $setName;
}
sub toCamelCase {
my $string = $_[0];
$string =~ s/\b([\w']+)\b/ucfirst($1)/ge;
$string =~ s/[-,\s\']//g;
$string =~ s/[\/]//g;
$string;
}
my $cardsFound = 0;
my %all_sets;
print ("Opening $dataFile\n");
open (DATA, $dataFile) || die "can't open $dataFile";
while(my $line = <DATA>) {
my @data = split('\\|', $line);
$cards{$data[0]}{$data[1]} = \@data;
if ($data[1] eq $setName) {
my $cardInfo = "$data[0],,,$data[2]";
push(@setCards, $cardInfo);
} else {
$all_sets {$data[1]} = 1;
}
}
# Fix up split cards
my $potentialSideA;
my @tempSetCards;
foreach $potentialSideA (sort @setCards) {
#print (">>$potentialSideA\n");
if ($potentialSideA =~ m/.*,,,(\d+)(a)$/) {
my $cardNumSideB = $1 . "b";
my $val;
foreach $val (sort @setCards) {
if ($val =~ m/$cardNumSideB$/) {
$potentialSideA =~ s/,,,.*//;
$val =~ s/,,,.*//;
# Add 'SideaSideb' to %cards
my $ds = $cards{$val}{$setName};
#print ("$potentialSideA$val,,,$cardNumSideB\n");
my @newCard;
push (@newCard, "$potentialSideA$val");
push (@newCard, "$setName");
push (@newCard, "SPLIT");
push (@newCard, @$ds[3]);
push (@newCard, "$potentialSideA // $val");
$cards{$newCard[0]}{$newCard[1]} = \@newCard;
$cardNumSideB =~ s/.$//;
push (@tempSetCards, "$potentialSideA$val,,,$cardNumSideB");
#print ("Adding in: $potentialSideA \/\/ $val,,,$cardNumSideB\n");
$cardsFound = $cardsFound - 1;
}
}
}
elsif ($potentialSideA =~ m/.*,,,(\d+)(b)$/) {
next;
}
else {
$cardsFound = $cardsFound + 1;
push (@tempSetCards, $potentialSideA);
}
}
@setCards = @tempSetCards;
close(DATA);
print "Number of cards found for set " . $setName . ": " . $cardsFound . "\n";
if ($cardsFound == 0) {
$setName =~ s/^(...).*/$1/;
my $poss;
my $foundPossibleSet = 0;
my $numPossibleSets = 0;
foreach $poss (sort keys (%all_sets)) {
$numPossibleSets++;
if ($poss =~ m/^$setName/i) {
print ("Did you possibly mean: $poss ?\n");
$foundPossibleSet = 1;
}
}
if (!$foundPossibleSet) {
print ("Couldn't find any matching set for '$setName'. \n");
}
print "(Note: Looked at $numPossibleSets sets in total).\nPress the enter key to exit.";
$setName = <STDIN>;
exit;
}
open (DATA, $setsFile) || die "can't open $setsFile";
while(my $line = <DATA>) {
my @data = split('\\|', $line);
$sets{$data[0]}= $data[1];
}
close(DATA);
open (DATA, $knownSetsFile) || die "can't open $knownSetsFile";
while(my $line = <DATA>) {
my @data = split('\\|', $line);
$knownSets{$data[0]}= $data[1];
}
close(DATA);
print ("Reading in existing cards in set\n");
open (SET_FILE, "../../mage/Mage.Sets/src/mage/sets/$knownSets{$setName}.java") || die "can't open $dataFile";
my %alreadyIn;
while (<SET_FILE>) {
my $line = $_;
if ($line =~ m/SetCardInfo.*\("(.*)", (\d+).*/)
{
$alreadyIn {$2} = $1;
}
}
close SET_FILE;
my $name_collectorid;
my %authors;
my %author_counts;
foreach $name_collectorid (sort @setCards)
{
my $cardName;
my $cardNr;
$name_collectorid =~ m/^(.*),,,(.*)$/;
$cardName = $1;
$cardNr = $2;
{
my $ds;
$ds = $cards{$cardName}{$setName};
my $className = toCamelCase($cardName);
my $setId = lc($cardName);
$setId =~ s/^(.).*/$1/;
my $fn = "..\\Mage.Sets\\src\\mage\\cards\\$setId\\$className.java";
if (@$ds[2] eq "SPLIT") {
my $oldCardName = $cardName;
$cardName = @$ds[4];
}
my $plus_cardName = $cardName;
$plus_cardName =~ s/ /+/img;
$plus_cardName =~ s/,/+/img;
$plus_cardName = "intext:\"$plus_cardName\"";
my $cmd = "find /I \"\@author\" $fn";
if (!exists ($alreadyIn{$cardNr})) {
if (-e $fn) {
my $output = `$cmd`;
chomp $output;
$output =~ s/^----.*\n//img;
$output =~ s/^.*author\s*//img;
$authors {$fn} = $output;
$author_counts {$output} ++;
}
} else {
if (-e $fn) {
my $output = `$cmd`;
chomp $output;
$output =~ s/^----.*\n//img;
$output =~ s/^.*.author\s*//img;
$authors {$fn} = $output;
$author_counts {$output} ++;
}
}
}
}
print "\n\n\nAuthor Counts:\n";
my $author;
foreach $author (sort (keys %author_counts)) {
if ($author !~ m/---/img) {
print ("$author --> $author_counts{$author}");
}
}
print ("\nData from reading: ../../mage/Mage.Sets/src/mage/sets/$knownSets{$setName}.java\n");
print "\n\nYou are done. Press the enter key to exit.";
$setName = <STDIN>;