1
0
Fork 0
mirror of https://github.com/correl/mage.git synced 2025-04-02 03:18:09 -09:00

Merge pull request from magefree/master

merge
This commit is contained in:
theelk801 2017-08-26 19:59:51 -04:00 committed by GitHub
commit 22d253acd7
16 changed files with 420 additions and 206 deletions

View file

@ -705,7 +705,7 @@ public class HumanPlayer extends PlayerImpl {
// it's a main phase
if (!skippedAtLeastOnce
|| (!playerId.equals(game.getActivePlayerId())
&& !this.getUserData().getUserSkipPrioritySteps().isStopOnAllMainPhases())) {
&& !controllingPlayer.getUserData().getUserSkipPrioritySteps().isStopOnAllMainPhases())) {
skippedAtLeastOnce = true;
if (passWithManaPoolCheck(game)) {
return false;
@ -726,7 +726,7 @@ public class HumanPlayer extends PlayerImpl {
// It's end of turn phase
if (!skippedAtLeastOnce
|| (playerId.equals(game.getActivePlayerId())
&& !this.getUserData().getUserSkipPrioritySteps().isStopOnAllEndPhases())) {
&& !controllingPlayer.getUserData().getUserSkipPrioritySteps().isStopOnAllEndPhases())) {
skippedAtLeastOnce = true;
if (passWithManaPoolCheck(game)) {
return false;
@ -834,7 +834,7 @@ public class HumanPlayer extends PlayerImpl {
return !controllingPlayer.getUserData().getUserSkipPrioritySteps().getOpponentTurn().isPhaseStepSet(game.getStep().getType());
}
} catch (NullPointerException ex) {
String isNull = userData == null ? "null" : "not null";
String isNull = controllingPlayer.getUserData() == null ? "null" : "not null";
logger.error("null pointer exception UserData = " + isNull);
}
return true;
@ -843,7 +843,7 @@ public class HumanPlayer extends PlayerImpl {
@Override
public TriggeredAbility chooseTriggeredAbility(List<TriggeredAbility> abilities, Game game) {
String autoOrderRuleText = null;
boolean autoOrderUse = getUserData().isAutoOrderTrigger();
boolean autoOrderUse = getControllingPlayersUserData(game).isAutoOrderTrigger();
while (!abort) {
// try to set trigger auto order
List<TriggeredAbility> abilitiesWithNoOrderSet = new ArrayList<>();
@ -1045,7 +1045,7 @@ public class HumanPlayer extends PlayerImpl {
while (!abort) {
if (passedAllTurns
|| passedUntilEndStepBeforeMyTurn
|| (!getUserData().getUserSkipPrioritySteps().isStopOnDeclareAttackersDuringSkipAction()
|| (!getControllingPlayersUserData(game).getUserSkipPrioritySteps().isStopOnDeclareAttackersDuringSkipAction()
&& (passedTurn
|| passedTurnSkipStack
|| passedUntilEndOfTurn
@ -1223,7 +1223,7 @@ public class HumanPlayer extends PlayerImpl {
FilterCreatureForCombatBlock filter = filterCreatureForCombatBlock.copy();
filter.add(new ControllerIdPredicate(defendingPlayerId));
if (game.getBattlefield().count(filter, null, playerId, game) == 0
&& !getUserData().getUserSkipPrioritySteps().isStopOnDeclareBlockerIfNoneAvailable()) {
&& !getControllingPlayersUserData(game).getUserSkipPrioritySteps().isStopOnDeclareBlockerIfNoneAvailable()) {
return;
}
while (!abort) {
@ -1420,7 +1420,7 @@ public class HumanPlayer extends PlayerImpl {
protected void activateAbility(LinkedHashMap<UUID, ? extends ActivatedAbility> abilities, MageObject object, Game game) {
updateGameStatePriority("activateAbility", game);
if (abilities.size() == 1
&& suppressAbilityPicker(abilities.values().iterator().next())) {
&& suppressAbilityPicker(abilities.values().iterator().next(), game)) {
ActivatedAbility ability = abilities.values().iterator().next();
if (!ability.getTargets().isEmpty()
|| !(ability.getCosts().size() == 1
@ -1452,8 +1452,8 @@ public class HumanPlayer extends PlayerImpl {
}
}
private boolean suppressAbilityPicker(ActivatedAbility ability) {
if (this.getUserData().isShowAbilityPickerForced()) {
private boolean suppressAbilityPicker(ActivatedAbility ability, Game game) {
if (getControllingPlayersUserData(game).isShowAbilityPickerForced()) {
if (ability instanceof PlayLandAbility) {
return true;
}

View file

@ -27,6 +27,13 @@
*/
package mage.server;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import mage.cards.repository.CardInfo;
import mage.cards.repository.CardRepository;
import mage.server.exceptions.UserNotFoundException;
@ -36,11 +43,6 @@ import mage.view.ChatMessage.MessageType;
import mage.view.ChatMessage.SoundToPlay;
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
*/
@ -51,6 +53,7 @@ public enum ChatManager {
private static final HashMap<String, String> userMessages = new HashMap<>();
private final ConcurrentHashMap<UUID, ChatSession> chatSessions = new ConcurrentHashMap<>();
private final ReadWriteLock lock = new ReentrantReadWriteLock();
public UUID createChatSession(String info) {
ChatSession chatSession = new ChatSession(info);
@ -68,6 +71,10 @@ public enum ChatManager {
}
public void clearUserMessageStorage() {
userMessages.clear();
}
public void leaveChat(UUID chatId, UUID userId) {
ChatSession chatSession = chatSessions.get(chatId);
if (chatSession != null && chatSession.hasUser(userId)) {
@ -81,7 +88,13 @@ public enum ChatManager {
if (chatSession != null) {
synchronized (chatSession) {
if (chatSessions.containsKey(chatId)) {
chatSessions.remove(chatId);
final Lock w = lock.writeLock();
w.lock();
try {
chatSessions.remove(chatId);
} finally {
w.unlock();
}
logger.trace("Chat removed - chatId: " + chatId);
} else {
logger.trace("Chat to destroy does not exist - chatId: " + chatId);
@ -263,10 +276,11 @@ public enum ChatManager {
* @param userId
* @param message
* @param color
* @throws mage.server.exceptions.UserNotFoundException
*/
public void broadcast(UUID userId, String message, MessageColor color) throws UserNotFoundException {
UserManager.instance.getUser(userId).ifPresent(user -> {
chatSessions.values()
getChatSessions()
.stream()
.filter(chat -> chat.hasUser(userId))
.forEach(session -> session.broadcast(user.getName(), message, color, true, MessageType.TALK, null));
@ -276,15 +290,15 @@ public enum ChatManager {
public void sendReconnectMessage(UUID userId) {
UserManager.instance.getUser(userId).ifPresent(user
-> chatSessions.values()
.stream()
.filter(chat -> chat.hasUser(userId))
.forEach(chatSession -> chatSession.broadcast(null, user.getName() + " has reconnected", MessageColor.BLUE, true, MessageType.STATUS, null)));
-> getChatSessions()
.stream()
.filter(chat -> chat.hasUser(userId))
.forEach(chatSession -> chatSession.broadcast(null, user.getName() + " has reconnected", MessageColor.BLUE, true, MessageType.STATUS, null)));
}
public void removeUser(UUID userId, DisconnectReason reason) {
for (ChatSession chatSession : chatSessions.values()) {
for (ChatSession chatSession : getChatSessions()) {
if (chatSession.hasUser(userId)) {
chatSession.kill(userId, reason);
}
@ -292,7 +306,13 @@ public enum ChatManager {
}
public List<ChatSession> getChatSessions() {
return new ArrayList<>(chatSessions.values());
final Lock r = lock.readLock();
r.lock();
try {
return new ArrayList<>(chatSessions.values());
} finally {
r.unlock();
}
}
}

View file

@ -30,6 +30,9 @@ package mage.server;
import java.text.DateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import mage.interfaces.callback.ClientCallback;
import mage.interfaces.callback.ClientCallbackMethod;
import mage.view.ChatMessage;
@ -46,6 +49,8 @@ public class ChatSession {
private static final Logger logger = Logger.getLogger(ChatSession.class);
private static final DateFormat timeFormatter = DateFormat.getTimeInstance(DateFormat.SHORT);
private final ReadWriteLock lock = new ReentrantReadWriteLock();
private final ConcurrentHashMap<UUID, String> clients = new ConcurrentHashMap<>();
private final UUID chatId;
private final Date createTime;
@ -61,7 +66,13 @@ public class ChatSession {
UserManager.instance.getUser(userId).ifPresent(user -> {
if (!clients.containsKey(userId)) {
String userName = user.getName();
clients.put(userId, userName);
final Lock w = lock.writeLock();
w.lock();
try {
clients.put(userId, userName);
} finally {
w.unlock();
}
broadcast(null, userName + " has joined (" + user.getClientVersion() + ')', MessageColor.BLUE, true, MessageType.STATUS, null);
logger.trace(userName + " joined chat " + chatId);
}
@ -77,8 +88,14 @@ public class ChatSession {
}
if (userId != null && clients.containsKey(userId)) {
String userName = clients.get(userId);
if (reason != DisconnectReason.LostConnection) { // for lost connection the user will be reconnected or session expire so no removeUserFromAllTables of chat yet
clients.remove(userId);
if (reason != DisconnectReason.LostConnection) { // for lost connection the user will be reconnected or session expire so no removeUserFromAllTablesAndChat of chat yet
final Lock w = lock.writeLock();
w.lock();
try {
clients.remove(userId);
} finally {
w.unlock();
}
logger.debug(userName + '(' + reason.toString() + ')' + " removed from chatId " + chatId);
}
String message = reason.getMessage();
@ -117,7 +134,15 @@ public class ChatSession {
if (!message.isEmpty()) {
Set<UUID> clientsToRemove = new HashSet<>();
ClientCallback clientCallback = new ClientCallback(ClientCallbackMethod.CHATMESSAGE, chatId, new ChatMessage(userName, message, (withTime ? timeFormatter.format(new Date()) : ""), color, messageType, soundToPlay));
for (UUID userId : clients.keySet()) {
List<UUID> chatUserIds = new ArrayList<>();
final Lock r = lock.readLock();
r.lock();
try {
chatUserIds.addAll(clients.keySet());
} finally {
r.unlock();
}
for (UUID userId : chatUserIds) {
Optional<User> user = UserManager.instance.getUser(userId);
if (user.isPresent()) {
user.get().fireCallback(clientCallback);
@ -125,7 +150,15 @@ public class ChatSession {
clientsToRemove.add(userId);
}
}
clients.keySet().removeAll(clientsToRemove);
if (!clientsToRemove.isEmpty()) {
final Lock w = lock.readLock();
w.lock();
try {
clients.keySet().removeAll(clientsToRemove);
} finally {
w.unlock();
}
}
}
}

View file

@ -356,7 +356,7 @@ public class Session {
} else {
logger.error("SESSION LOCK - kill: userId " + userId);
}
UserManager.instance.removeUserFromAllTables(userId, reason);
UserManager.instance.removeUserFromAllTablesAndChat(userId, reason);
} catch (InterruptedException ex) {
logger.error("SESSION LOCK - kill: userId " + userId, ex);
} finally {

View file

@ -511,7 +511,7 @@ public class TableController {
if (this.userId != null && this.userId.equals(userId) // tourn. sub tables have no creator user
&& (table.getState() == TableState.WAITING
|| table.getState() == TableState.READY_TO_START)) {
// table not started yet and user is the owner, removeUserFromAllTables the table
// table not started yet and user is the owner, removeUserFromAllTablesAndChat the table
TableManager.instance.removeTable(table.getId());
} else {
UUID playerId = userPlayerMap.get(userId);
@ -826,7 +826,7 @@ public class TableController {
}
user.showUserMessage("Match info", sb.toString());
}
// removeUserFromAllTables table from user - table manager holds table for display of finished matches
// removeUserFromAllTablesAndChat table from user - table manager holds table for display of finished matches
if (!table.isTournamentSubTable()) {
user.removeTable(entry.getValue());
}
@ -913,7 +913,7 @@ public class TableController {
return false;
}
} else {
// check if table creator is still a valid user, if not removeUserFromAllTables table
// check if table creator is still a valid user, if not removeUserFromAllTablesAndChat table
return UserManager.instance.getUser(userId).isPresent();
}
}

View file

@ -78,6 +78,7 @@ public enum TableManager {
TableManager() {
expireExecutor.scheduleAtFixedRate(() -> {
try {
ChatManager.instance.clearUserMessageStorage();
checkTableHealthState();
} catch (Exception ex) {
logger.fatal("Check table health state job error:", ex);
@ -161,7 +162,7 @@ public enum TableManager {
}
}
// removeUserFromAllTables user from all tournament sub tables
// removeUserFromAllTablesAndChat user from all tournament sub tables
public void userQuitTournamentSubTables(UUID userId) {
for (TableController controller : controllers.values()) {
if (controller.getTable() != null) {
@ -174,7 +175,7 @@ public enum TableManager {
}
}
// removeUserFromAllTables user from all sub tables of a tournament
// removeUserFromAllTablesAndChat user from all sub tables of a tournament
public void userQuitTournamentSubTables(UUID tournamentId, UUID userId) {
for (TableController controller : controllers.values()) {
if (controller.getTable().isTournamentSubTable() && controller.getTable().getTournament().getId().equals(tournamentId)) {
@ -386,8 +387,8 @@ public enum TableManager {
for (Table table : tableCopy) {
try {
if (table.getState() != TableState.FINISHED
&& ((System.currentTimeMillis() - table.getStartTime().getTime()) / 1000) > 30) { // removeUserFromAllTables only if table started longer than 30 seconds ago
// removeUserFromAllTables tables and games not valid anymore
&& ((System.currentTimeMillis() - table.getStartTime().getTime()) / 1000) > 30) { // removeUserFromAllTablesAndChat only if table started longer than 30 seconds ago
// removeUserFromAllTablesAndChat tables and games not valid anymore
logger.debug(table.getId() + " [" + table.getName() + "] " + formatter.format(table.getStartTime() == null ? table.getCreateTime() : table.getCreateTime()) + " (" + table.getState().toString() + ") " + (table.isTournament() ? "- Tournament" : ""));
getController(table.getId()).ifPresent(tableController -> {
if ((table.isTournament() && !tableController.isTournamentStillValid())

View file

@ -29,6 +29,9 @@ package mage.server;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import mage.server.User.UserState;
import mage.server.record.UserStats;
import mage.server.record.UserStatsRepository;
@ -54,6 +57,7 @@ public enum UserManager {
private static final Logger LOGGER = Logger.getLogger(UserManager.class);
private final ReadWriteLock lock = new ReentrantReadWriteLock();
private final ConcurrentHashMap<UUID, User> users = new ConcurrentHashMap<>();
private static final ExecutorService USER_EXECUTOR = ThreadExecutor.instance.getCallExecutor();
@ -69,7 +73,13 @@ public enum UserManager {
return Optional.empty(); //user already exists
}
User user = new User(userName, host, authorizedUser);
users.put(user.getId(), user);
final Lock w = lock.writeLock();
w.lock();
try {
users.put(user.getId(), user);
} finally {
w.unlock();
}
return Optional.of(user);
}
@ -83,17 +93,32 @@ public enum UserManager {
}
public Optional<User> getUserByName(String userName) {
Optional<User> u = users.values().stream().filter(user -> user.getName().equals(userName))
.findFirst();
if (u.isPresent()) {
return u;
} else {
return Optional.empty();
final Lock r = lock.readLock();
r.lock();
try {
Optional<User> u = users.values().stream().filter(user -> user.getName().equals(userName))
.findFirst();
if (u.isPresent()) {
return u;
} else {
return Optional.empty();
}
} finally {
r.unlock();
}
}
public Collection<User> getUsers() {
return users.values();
ArrayList<User> userList = new ArrayList<>();
final Lock r = lock.readLock();
r.lock();
try {
userList.addAll(users.values());
} finally {
r.unlock();
}
return userList;
}
public boolean connectToSession(String sessionId, UUID userId) {
@ -112,13 +137,10 @@ public enum UserManager {
if (user.isPresent()) {
user.get().setSessionId("");
if (reason == DisconnectReason.Disconnected) {
removeUserFromAllTables(userId, reason);
removeUserFromAllTablesAndChat(userId, reason);
user.get().setUserState(UserState.Offline);
}
}
if (userId != null) {
ChatManager.instance.removeUser(userId, reason);
}
}
public boolean isAdmin(UUID userId) {
@ -131,7 +153,7 @@ public enum UserManager {
return false;
}
public void removeUserFromAllTables(final UUID userId, final DisconnectReason reason) {
public void removeUserFromAllTablesAndChat(final UUID userId, final DisconnectReason reason) {
if (userId != null) {
getUser(userId).ifPresent(user
-> USER_EXECUTOR.execute(
@ -139,6 +161,7 @@ public enum UserManager {
try {
LOGGER.info("USER REMOVE - " + user.getName() + " (" + reason.toString() + ") userId: " + userId + " [" + user.getGameInfo() + ']');
user.removeUserFromAllTables(reason);
ChatManager.instance.removeUser(user.getId(), reason);
LOGGER.debug("USER REMOVE END - " + user.getName());
} catch (Exception ex) {
handleException(ex);
@ -173,7 +196,16 @@ public enum UserManager {
Calendar calendarRemove = Calendar.getInstance();
calendarRemove.add(Calendar.MINUTE, -8);
List<User> toRemove = new ArrayList<>();
for (User user : users.values()) {
logger.info("Start Check Expired");
ArrayList<User> userList = new ArrayList<>();
final Lock r = lock.readLock();
r.lock();
try {
userList.addAll(users.values());
} finally {
r.unlock();
}
for (User user : userList) {
try {
if (user.getUserState() == UserState.Offline) {
if (user.isExpired(calendarRemove.getTime())) {
@ -185,7 +217,7 @@ public enum UserManager {
user.lostConnection();
disconnect(user.getId(), DisconnectReason.BecameInactive);
}
removeUserFromAllTables(user.getId(), DisconnectReason.SessionExpired);
removeUserFromAllTablesAndChat(user.getId(), DisconnectReason.SessionExpired);
user.setUserState(UserState.Offline);
// Remove the user from all tournaments
@ -195,9 +227,17 @@ public enum UserManager {
handleException(ex);
}
}
for (User user : toRemove) {
users.remove(user.getId());
logger.info("Users to remove " + toRemove.size());
final Lock w = lock.readLock();
w.lock();
try {
for (User user : toRemove) {
users.remove(user.getId());
}
} finally {
w.unlock();
}
logger.info("End Check Expired");
} catch (Exception ex) {
handleException(ex);
}

View file

@ -95,7 +95,7 @@ public class GamesRoomImpl extends RoomImpl implements GamesRoom, Serializable {
} else if (matchList.size() < 50) {
matchList.add(new MatchView(table));
} else {
// more since 50 matches finished since this match so removeUserFromAllTables it
// more since 50 matches finished since this match so removeUserFromAllTablesAndChat it
if (table.isTournament()) {
TournamentManager.instance.removeTournament(table.getTournament().getId());
}

View file

@ -51,6 +51,7 @@ public class JeeringHomunculus extends CardImpl {
this.toughness = new MageInt(4);
// When Jeering Homunculus enters the battlefield, you may goad target creature.
// (Until your next turn, that creature attacks each combat if able and attacks a player other than you if able.)
Ability ability = new EntersBattlefieldTriggeredAbility(new GoadTargetEffect(), true);
ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability);

View file

@ -28,11 +28,10 @@
package mage.cards.t;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ExileSpellEffect;
import mage.abilities.effects.common.NameACardEffect;
import mage.abilities.effects.common.continuous.GainAbilityControllerEffect;
import mage.abilities.effects.common.continuous.LifeTotalCantChangeControllerEffect;
import mage.abilities.keyword.ProtectionAbility;
@ -41,9 +40,8 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.filter.FilterObject;
import mage.filter.common.FilterControlledPermanent;
import mage.filter.predicate.mageobject.NamePredicate;
import mage.filter.FilterCard;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
@ -58,7 +56,8 @@ public class TeferisProtection extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{W}");
// Until your next turn, your life total can't change, and you have protection from everything. All permanents you control phase out. (While they're phased out, they're treated as though they don't exist. They phase in before you untap during your untap step.)
this.getSpellAbility().addEffect(new LifeTotalCantChangeControllerEffect(Duration.UntilYourNextTurn));
this.getSpellAbility().addEffect(new LifeTotalCantChangeControllerEffect(Duration.UntilYourNextTurn)
.setText("Until your next turn, your life total can't change"));
this.getSpellAbility().addEffect(new TeferisProtectionEffect());
this.getSpellAbility().addEffect(new TeferisProtectionPhaseOutEffect());
@ -78,9 +77,31 @@ public class TeferisProtection extends CardImpl {
class TeferisProtectionEffect extends OneShotEffect {
/**
* 25.08.2017 The following rulings focus on the protection from keyword
*
* 25.08.2017 If a player has protection from everything, it means three
* things: 1) All damage that would be dealt to that player is prevented. 2)
* Auras cant be attached to that player. 3) That player cant be the
* target of spells or abilities.
*
* 25.08.2017 Nothing other than the specified events are prevented or
* illegal. An effect that doesnt target you could still cause you to
* discard cards, for example. Creatures can still attack you while you have
* protection from everything, although combat damage that they would deal
* to you will be prevented.
*
* 25.08.2017 Gaining protection from everything causes a spell or ability
* on the stack to have an illegal target if it targets you. As a spell or
* ability tries to resolve, if all its targets are illegal, that spell or
* ability is countered and none of its effects happen, including effects
* unrelated to the target. If at least one target is still legal, the spell
* or ability does as much as it can to the remaining legal targets, and its
* other effects still happen.
*/
public TeferisProtectionEffect() {
super(Outcome.Protect);
staticText = "<br/><br/>You have protection from everything<i>(You can't be targeted, dealt damage, or enchanted by anything.)</i>";
staticText = ", and you have protection from everything";
}
public TeferisProtectionEffect(final TeferisProtectionEffect effect) {
@ -90,12 +111,8 @@ class TeferisProtectionEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
String cardName = (String) game.getState().getValue(source.getSourceId().toString() + NameACardEffect.INFO_KEY);
if (controller != null) {
FilterObject filter = new FilterObject("the name [everything]");
filter.add(new NamePredicate("everything"));
ContinuousEffect effect = new GainAbilityControllerEffect(new ProtectionAbility(filter), Duration.Custom);
game.addEffect(effect, source);
game.addEffect(new GainAbilityControllerEffect(new TeferisProtectionAbility(), Duration.UntilYourNextTurn), source);
return true;
}
return false;
@ -107,9 +124,33 @@ class TeferisProtectionEffect extends OneShotEffect {
}
}
class TeferisProtectionPhaseOutEffect extends OneShotEffect {
class TeferisProtectionAbility extends ProtectionAbility {
private FilterControlledPermanent permanentsYouControl = new FilterControlledPermanent("all permanents you control");
public TeferisProtectionAbility() {
super(new FilterCard("everything"));
}
public TeferisProtectionAbility(final TeferisProtectionAbility ability) {
super(ability);
}
@Override
public TeferisProtectionAbility copy() {
return new TeferisProtectionAbility(this);
}
@Override
public String getRule() {
return "Protection from everything";
}
@Override
public boolean canTarget(MageObject source, Game game) {
return false;
}
}
class TeferisProtectionPhaseOutEffect extends OneShotEffect {
public TeferisProtectionPhaseOutEffect() {
super(Outcome.Benefit);
@ -129,7 +170,7 @@ class TeferisProtectionPhaseOutEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
for (Permanent permanent : game.getBattlefield().getActivePermanents(permanentsYouControl, controller.getId(), game)) {
for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_CONTROLLED_PERMANENT, controller.getId(), game)) {
permanent.phaseOut(game);
}
return true;

View file

@ -29,12 +29,12 @@ package mage.cards.t;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;
import mage.MageInt;
import mage.MageObjectReference;
import mage.abilities.Ability;
import mage.abilities.common.BeginningOfCombatTriggeredAbility;
import mage.abilities.effects.ContinuousEffect;
@ -46,10 +46,12 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.TargetController;
import mage.constants.WatcherScope;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.targetpointer.FixedTarget;
import mage.util.RandomUtil;
@ -64,7 +66,7 @@ public class TerritorialHellkite extends CardImpl {
public TerritorialHellkite(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{R}");
this.subtype.add("Dragon");
this.subtype.add(SubType.DRAGON);
this.power = new MageInt(6);
this.toughness = new MageInt(5);
@ -90,7 +92,8 @@ public class TerritorialHellkite extends CardImpl {
class AttackedLastCombatWatcher extends Watcher {
public final Map<UUID, UUID> attackedLastCombatPlayers = new HashMap<>();
// Map<lastCombatOfPlayerId, Map<attackingCreature, attackedPlayerId>>
public final Map<UUID, Map<MageObjectReference, UUID>> attackedLastCombatPlayers = new HashMap<>();
public AttackedLastCombatWatcher() {
super(AttackedLastCombatWatcher.class.getSimpleName(), WatcherScope.GAME);
@ -98,32 +101,34 @@ class AttackedLastCombatWatcher extends Watcher {
public AttackedLastCombatWatcher(final AttackedLastCombatWatcher watcher) {
super(watcher);
for (Entry<UUID, UUID> entry : watcher.attackedLastCombatPlayers.entrySet()) {
attackedLastCombatPlayers.put(entry.getKey(), entry.getValue());
for (Entry<UUID, Map<MageObjectReference, UUID>> entry : watcher.attackedLastCombatPlayers.entrySet()) {
Map<MageObjectReference, UUID> allAttackersCopy = new HashMap<>();
allAttackersCopy.putAll(entry.getValue());
attackedLastCombatPlayers.put(entry.getKey(), allAttackersCopy);
}
}
@Override
public void watch(GameEvent event, Game game) {
//TODO: this will have problems if the creature is stolen and then given back before the original controller's next combat
if (event.getType() == GameEvent.EventType.DECLARE_ATTACKERS_STEP_PRE) {
if (!attackedLastCombatPlayers.keySet().isEmpty()) {
Iterator<Map.Entry<UUID, UUID>> attackers = attackedLastCombatPlayers.entrySet().iterator();
while (attackers.hasNext()) {
Map.Entry<UUID, UUID> attacker = attackers.next();
if (game.getPermanent(attacker.getKey()).getControllerId().equals(game.getActivePlayerId())) {
attackers.remove();
}
}
}
// Remove previous attacking creatures of the current combat's player if info exists
attackedLastCombatPlayers.remove(game.getCombat().getAttackingPlayerId());
}
if (event.getType() == GameEvent.EventType.ATTACKER_DECLARED) {
attackedLastCombatPlayers.put(event.getSourceId(), game.getCombat().getDefenderId(event.getSourceId()));
// remember which attacker attacked which player
Map<MageObjectReference, UUID> attackedPlayers = new HashMap<>();
for (UUID attackerId : game.getCombat().getAttackers()) {
Permanent attacker = game.getPermanent(attackerId);
if (attacker != null) {
attackedPlayers.put(new MageObjectReference(attacker, game), game.getCombat().getDefenderId(attackerId));
}
}
attackedLastCombatPlayers.put(game.getCombat().getAttackingPlayerId(), attackedPlayers);
}
}
public Map<UUID, UUID> getAttackedLastCombatPlayers() {
return this.attackedLastCombatPlayers;
public Map<MageObjectReference, UUID> getAttackedLastCombatPlayers(UUID combatPlayerId) {
return attackedLastCombatPlayers.get(combatPlayerId);
}
@Override
@ -152,22 +157,20 @@ class AttackIfAbleTargetRandoOpponentSourceEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
Permanent sourcePermanent = game.getPermanent(source.getSourceId());
AttackedLastCombatWatcher watcher = (AttackedLastCombatWatcher) game.getState().getWatchers().get(AttackedLastCombatWatcher.class.getSimpleName());
if (controller != null && sourcePermanent != null && watcher != null) {
List<UUID> opponents = new ArrayList<>();
AttackedLastCombatWatcher watcher = (AttackedLastCombatWatcher) game.getState().getWatchers().get(AttackedLastCombatWatcher.class.getSimpleName());
if (watcher != null) {
boolean ignoreMe;
Map<MageObjectReference, UUID> attackedPlayers = watcher.getAttackedLastCombatPlayers(source.getControllerId());
MageObjectReference mor = new MageObjectReference(sourcePermanent, game);
if (attackedPlayers == null) {
opponents.addAll(game.getOpponents(controller.getId()));
} else {
for (UUID opp : game.getOpponents(controller.getId())) {
ignoreMe = false;
if (watcher.getAttackedLastCombatPlayers().getOrDefault(source.getSourceId(), source.getControllerId()).equals(opp)) {
ignoreMe = true;
}
if (!ignoreMe) {
if (!opp.equals(attackedPlayers.getOrDefault(mor, null))) {
opponents.add(opp);
}
}
} else {
opponents.addAll(game.getOpponents(controller.getId()));
}
if (!opponents.isEmpty()) {
Player opponent = game.getPlayer(opponents.get(RandomUtil.nextInt(opponents.size())));
@ -175,12 +178,15 @@ class AttackIfAbleTargetRandoOpponentSourceEffect extends OneShotEffect {
ContinuousEffect effect = new AttacksIfAbleTargetPlayerSourceEffect();
effect.setTargetPointer(new FixedTarget(opponent.getId()));
game.addEffect(effect, source);
return true;
game.informPlayers(sourcePermanent.getLogName() + " has to attack " + opponent.getLogName() + ".");
}
} else {
game.getPermanent(source.getSourceId()).tap(game);
game.informPlayers(sourcePermanent.getLogName() + " can't attack an opponent it didn't attack last combat.");
sourcePermanent.tap(game);
}
return true;
}
return false;
}
}

View file

@ -51,7 +51,7 @@ import mage.target.TargetPermanent;
public class VampireHexmage extends CardImpl {
public VampireHexmage(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{B}{B}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}{B}");
this.subtype.add("Vampire");
this.subtype.add("Shaman");
@ -77,12 +77,12 @@ public class VampireHexmage extends CardImpl {
class VampireHexmageEffect extends OneShotEffect {
VampireHexmageEffect ( ) {
VampireHexmageEffect() {
super(Outcome.Benefit);
staticText = "Remove all counters from target permanent";
}
VampireHexmageEffect ( VampireHexmageEffect effect ) {
VampireHexmageEffect(VampireHexmageEffect effect) {
super(effect);
}
@ -93,18 +93,13 @@ class VampireHexmageEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
TargetPermanent target = (TargetPermanent)source.getTargets().get(0);
Permanent permanent = game.getPermanent(target.getFirstTarget());
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (permanent != null) {
for(Counter counter : permanent.getCounters(game).values()){
for (Counter counter : permanent.getCounters(game).copy().values()) { // copy to prevent ConcurrentModificationException
permanent.removeCounters(counter, game);
}
return true;
}
return false;
}

View file

@ -53,16 +53,16 @@ public class PutPermanentOnBattlefieldEffect extends OneShotEffect {
} else {
player = game.getPlayer(source.getControllerId());
}
String choiceText = "Put " + filter.getMessage() + " from your hand onto the battlefield?";
if (player == null || !player.chooseUse(Outcome.PutCardInPlay, choiceText, source, game)) {
if (player == null) {
return false;
}
TargetCardInHand target = new TargetCardInHand(filter);
if (player.choose(Outcome.PutCreatureInPlay, target, source.getSourceId(), game)) {
Card card = game.getCard(target.getFirstTarget());
if (card != null) {
return player.moveCards(card, Zone.BATTLEFIELD, source, game);
if (player.chooseUse(Outcome.PutCardInPlay, "Put " + filter.getMessage() + " from your hand onto the battlefield?", source, game)) {
TargetCardInHand target = new TargetCardInHand(filter);
if (player.choose(Outcome.PutCreatureInPlay, target, source.getSourceId(), game)) {
Card card = game.getCard(target.getFirstTarget());
if (card != null) {
return player.moveCards(card, Zone.BATTLEFIELD, source, game);
}
}
}
return true;

View file

@ -66,12 +66,8 @@ public class TributeAbility extends EntersBattlefieldAbility {
@Override
public String getRule() {
StringBuilder sb = new StringBuilder("Tribute ");
sb.append(tributeValue);
sb.append(" <i>(As this creature enters the battlefield, an opponent of your choice may put ");
sb.append(tributeValue);
sb.append(" +1/+1 counter on it.)</i>");
return sb.toString();
return "Tribute " + tributeValue + " <i>(As this creature enters the battlefield, an opponent of your choice may put "
+ tributeValue + " +1/+1 counter on it.)</i>";
}
}

View file

@ -23,7 +23,6 @@ import mage.filter.predicate.permanent.TokenPredicate;
*/
public final class StaticFilters {
public static final FilterSpiritOrArcaneCard SPIRIT_OR_ARCANE_CARD = new FilterSpiritOrArcaneCard();
public static final FilterArtifactOrEnchantmentPermanent ARTIFACT_OR_ENCHANTMENT_PERMANENT = new FilterArtifactOrEnchantmentPermanent();
public static final FilterEnchantmentPermanent FILTER_ENCHANTMENT_PERMANENT = new FilterEnchantmentPermanent();
@ -37,6 +36,8 @@ public final class StaticFilters {
public static final FilterPermanent FILTER_PERMANENT_ARTIFACT_OR_CREATURE = new FilterPermanent("artifact or creature");
public static final FilterPermanent FILTER_PERMANENT_ARTIFACT_CREATURE_OR_ENCHANTMENT = new FilterPermanent("artifact, creature, or enchantment");
public static final FilterPermanent FILTER_PERMANENT_ARTIFACT_CREATURE_ENCHANTMENT_OR_LAND = new FilterPermanent("artifact, creature, enchantment, or land");
public static final FilterControlledPermanent FILTER_CONTROLLED_PERMANENT = new FilterControlledPermanent();
public static final FilterControlledPermanent FILTER_CONTROLLED_PERMANENT_ARTIFACT = new FilterControlledArtifactPermanent();
public static final FilterControlledPermanent FILTER_CONTROLLED_PERMANENT_ARTIFACT_OR_CREATURE = new FilterControlledPermanent("artifact or creature you control");
@ -67,8 +68,6 @@ public final class StaticFilters {
public static final FilterPermanent FILTER_ATTACKING_CREATURES = new FilterCreaturePermanent("attacking creatures");
public static final FilterPermanent FILTER_AURA = new FilterPermanent();
public static final FilterPermanent FILTER_EQUIPMENT = new FilterPermanent();
public static final FilterPermanent FILTER_FORTIFICATION = new FilterPermanent();
@ -91,7 +90,6 @@ public final class StaticFilters {
FILTER_CONTROLLED_PERMANENT_NON_LAND.add(
Predicates.not(new CardTypePredicate(CardType.LAND)));
FILTER_CREATURE_TOKENS.add(new TokenPredicate());
FILTER_ATTACKING_CREATURES.add(new AttackingPredicate());

View file

@ -27,6 +27,10 @@
*/
package mage.players;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.Map.Entry;
import mage.ConditionalMana;
import mage.MageObject;
import mage.Mana;
@ -50,6 +54,11 @@ import mage.cards.CardsImpl;
import mage.cards.SplitCard;
import mage.cards.decks.Deck;
import mage.constants.*;
import static mage.constants.Zone.BATTLEFIELD;
import static mage.constants.Zone.EXILED;
import static mage.constants.Zone.GRAVEYARD;
import static mage.constants.Zone.HAND;
import static mage.constants.Zone.LIBRARY;
import mage.counters.Counter;
import mage.counters.CounterType;
import mage.counters.Counters;
@ -87,11 +96,6 @@ import mage.util.GameLog;
import mage.util.RandomUtil;
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 {
private static final Logger logger = Logger.getLogger(PlayerImpl.class);
@ -966,6 +970,10 @@ public abstract class PlayerImpl implements Player, Serializable {
ability = chooseSpellAbilityForCast(ability, game, noMana);
}
//20091005 - 601.2a
if (ability.getSourceId() == null) {
logger.error("Ability without sourceId turn " + game.getTurnNum() + ". Ability: " + ability.getRule());
return false;
}
Card card = game.getCard(ability.getSourceId());
if (card != null) {
if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.CAST_SPELL, ability.getId(), ability.getSourceId(), playerId), ability)) {
@ -1770,51 +1778,59 @@ public abstract class PlayerImpl implements Player, Serializable {
@SuppressWarnings({"null", "ConstantConditions"})
private int doDamage(int damage, UUID sourceId, Game game, boolean combatDamage, boolean preventable, List<UUID> appliedEffects) {
if (damage > 0 && canDamage(game.getObject(sourceId), game)) {
GameEvent event = new DamagePlayerEvent(playerId, sourceId, playerId, damage, preventable, combatDamage);
event.setAppliedEffects(appliedEffects);
if (!game.replaceEvent(event)) {
int actualDamage = event.getAmount();
if (actualDamage > 0) {
UUID sourceControllerId = null;
Abilities sourceAbilities = null;
MageObject source = game.getPermanentOrLKIBattlefield(sourceId);
if (source == null) {
StackObject stackObject = game.getStack().getStackObject(sourceId);
if (stackObject != null) {
source = stackObject.getStackAbility().getSourceObject(game);
if (damage > 0) {
if (canDamage(game.getObject(sourceId), game)) {
GameEvent event = new DamagePlayerEvent(playerId, sourceId, playerId, damage, preventable, combatDamage);
event.setAppliedEffects(appliedEffects);
if (!game.replaceEvent(event)) {
int actualDamage = event.getAmount();
if (actualDamage > 0) {
UUID sourceControllerId = null;
Abilities sourceAbilities = null;
MageObject source = game.getPermanentOrLKIBattlefield(sourceId);
if (source == null) {
StackObject stackObject = game.getStack().getStackObject(sourceId);
if (stackObject != null) {
source = stackObject.getStackAbility().getSourceObject(game);
} else {
source = game.getObject(sourceId);
}
if (source instanceof Spell) {
sourceAbilities = ((Spell) source).getAbilities(game);
sourceControllerId = ((Spell) source).getControllerId();
} else if (source instanceof Card) {
sourceAbilities = ((Card) source).getAbilities(game);
sourceControllerId = ((Card) source).getOwnerId();
} else if (source instanceof CommandObject) {
sourceControllerId = ((CommandObject) source).getControllerId();
sourceAbilities = ((CommandObject) source).getAbilities();
}
} else {
source = game.getObject(sourceId);
sourceAbilities = ((Permanent) source).getAbilities(game);
sourceControllerId = ((Permanent) source).getControllerId();
}
if (source instanceof Spell) {
sourceAbilities = ((Spell) source).getAbilities(game);
sourceControllerId = ((Spell) source).getControllerId();
} else if (source instanceof Card) {
sourceAbilities = ((Card) source).getAbilities(game);
sourceControllerId = ((Card) source).getOwnerId();
} else if (source instanceof CommandObject) {
sourceControllerId = ((CommandObject) source).getControllerId();
sourceAbilities = ((CommandObject) source).getAbilities();
if (sourceAbilities != null && sourceAbilities.containsKey(InfectAbility.getInstance().getId())) {
addCounters(CounterType.POISON.createInstance(actualDamage), game);
} else {
GameEvent damageToLifeLossEvent = new GameEvent(EventType.DAMAGE_CAUSES_LIFE_LOSS, playerId, sourceId, playerId, actualDamage, combatDamage);
if (!game.replaceEvent(damageToLifeLossEvent)) {
this.loseLife(damageToLifeLossEvent.getAmount(), game, combatDamage);
}
}
} else {
sourceAbilities = ((Permanent) source).getAbilities(game);
sourceControllerId = ((Permanent) source).getControllerId();
}
if (sourceAbilities != null && sourceAbilities.containsKey(InfectAbility.getInstance().getId())) {
addCounters(CounterType.POISON.createInstance(actualDamage), game);
} else {
GameEvent damageToLifeLossEvent = new GameEvent(EventType.DAMAGE_CAUSES_LIFE_LOSS, playerId, sourceId, playerId, actualDamage, combatDamage);
if (!game.replaceEvent(damageToLifeLossEvent)) {
this.loseLife(damageToLifeLossEvent.getAmount(), game, combatDamage);
if (sourceAbilities != null && sourceAbilities.containsKey(LifelinkAbility.getInstance().getId())) {
Player player = game.getPlayer(sourceControllerId);
player.gainLife(actualDamage, game);
}
game.fireEvent(new DamagedPlayerEvent(playerId, sourceId, playerId, actualDamage, combatDamage));
return actualDamage;
}
if (sourceAbilities != null && sourceAbilities.containsKey(LifelinkAbility.getInstance().getId())) {
Player player = game.getPlayer(sourceControllerId);
player.gainLife(actualDamage, game);
}
game.fireEvent(new DamagedPlayerEvent(playerId, sourceId, playerId, actualDamage, combatDamage));
return actualDamage;
}
} else {
MageObject sourceObject = game.getObject(sourceId);
game.informPlayers(damage + " damage "
+ (sourceObject == null ? "" : "from " + sourceObject.getLogName())
+ "to " + getLogName()
+ (damage > 1 ? " were" : "was") + " prevented because of protection.");
}
}
return 0;
@ -2924,15 +2940,27 @@ public abstract class PlayerImpl implements Player, Serializable {
return this.userData;
}
public UserData getControllingPlayersUserData(Game game) {
if (isGameUnderControl()) {
Player player = game.getPlayer(getTurnControlledBy());
if (player.isHuman()) {
return player.getUserData();
}
}
return this.userData;
}
@Override
public void setUserData(UserData userData) {
public void setUserData(UserData userData
) {
this.userData = userData;
getManaPool().setAutoPayment(userData.isManaPoolAutomatic());
getManaPool().setAutoPaymentRestricted(userData.isManaPoolAutomaticRestricted());
}
@Override
public void addAction(String action) {
public void addAction(String action
) {
// do nothing
}
@ -2942,7 +2970,8 @@ public abstract class PlayerImpl implements Player, Serializable {
}
@Override
public void setAllowBadMoves(boolean allowBadMoves) {
public void setAllowBadMoves(boolean allowBadMoves
) {
// do nothing
}
@ -2952,17 +2981,21 @@ public abstract class PlayerImpl implements Player, Serializable {
}
@Override
public void setCanPayLifeCost(boolean canPayLifeCost) {
public void setCanPayLifeCost(boolean canPayLifeCost
) {
this.canPayLifeCost = canPayLifeCost;
}
@Override
public boolean canPaySacrificeCost(Permanent permanent, UUID sourceId, UUID controllerId, Game game) {
public boolean canPaySacrificeCost(Permanent permanent, UUID sourceId,
UUID controllerId, Game game
) {
return sacrificeCostFilter == null || !sacrificeCostFilter.match(permanent, sourceId, controllerId, game);
}
@Override
public void setCanPaySacrificeCostFilter(FilterPermanent filter) {
public void setCanPaySacrificeCostFilter(FilterPermanent filter
) {
this.sacrificeCostFilter = filter;
}
@ -2977,7 +3010,8 @@ public abstract class PlayerImpl implements Player, Serializable {
}
@Override
public void setLoseByZeroOrLessLife(boolean loseByZeroOrLessLife) {
public void setLoseByZeroOrLessLife(boolean loseByZeroOrLessLife
) {
this.loseByZeroOrLessLife = loseByZeroOrLessLife;
}
@ -2987,7 +3021,8 @@ public abstract class PlayerImpl implements Player, Serializable {
}
@Override
public void setPlayCardsFromGraveyard(boolean playCardsFromGraveyard) {
public void setPlayCardsFromGraveyard(boolean playCardsFromGraveyard
) {
this.canPlayCardsFromGraveyard = playCardsFromGraveyard;
}
@ -3014,12 +3049,14 @@ public abstract class PlayerImpl implements Player, Serializable {
}
@Override
public void setStoredBookmark(int storedBookmark) {
public void setStoredBookmark(int storedBookmark
) {
this.storedBookmark = storedBookmark;
}
@Override
public synchronized void resetStoredBookmark(Game game) {
public synchronized void resetStoredBookmark(Game game
) {
if (this.storedBookmark != -1) {
game.removeBookmark(this.storedBookmark);
}
@ -3027,7 +3064,8 @@ public abstract class PlayerImpl implements Player, Serializable {
}
@Override
public boolean lookAtFaceDownCard(Card card, Game game) {
public boolean lookAtFaceDownCard(Card card, Game game
) {
if (game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.LOOK_AT_FACE_DOWN, this.getId(), game)) {
if (chooseUse(Outcome.Benefit, "Look at that card?", null, game)) {
Cards cards = new CardsImpl(card);
@ -3039,7 +3077,8 @@ public abstract class PlayerImpl implements Player, Serializable {
}
@Override
public void setPriorityTimeLeft(int timeLeft) {
public void setPriorityTimeLeft(int timeLeft
) {
priorityTimeLeft = timeLeft;
}
@ -3064,7 +3103,8 @@ public abstract class PlayerImpl implements Player, Serializable {
}
@Override
public void setReachedNextTurnAfterLeaving(boolean reachedNextTurnAfterLeaving) {
public void setReachedNextTurnAfterLeaving(boolean reachedNextTurnAfterLeaving
) {
this.reachedNextTurnAfterLeaving = reachedNextTurnAfterLeaving;
}
@ -3074,12 +3114,14 @@ public abstract class PlayerImpl implements Player, Serializable {
}
@Override
public boolean canJoinTable(Table table) {
public boolean canJoinTable(Table table
) {
return !table.userIsBanned(name);
}
@Override
public void addCommanderId(UUID commanderId) {
public void addCommanderId(UUID commanderId
) {
this.commandersIds.add(commanderId);
}
@ -3089,12 +3131,17 @@ public abstract class PlayerImpl implements Player, Serializable {
}
@Override
public boolean moveCards(Card card, Zone toZone, Ability source, Game game) {
public boolean moveCards(Card card, Zone toZone,
Ability source, Game game
) {
return moveCards(card, toZone, source, game, false, false, false, null);
}
@Override
public boolean moveCards(Card card, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, List<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<>();
if (card != null) {
cardList.add(card);
@ -3103,17 +3150,24 @@ public abstract class PlayerImpl implements Player, Serializable {
}
@Override
public boolean moveCards(Cards cards, Zone toZone, Ability source, Game game) {
public boolean moveCards(Cards cards, Zone toZone,
Ability source, Game game
) {
return moveCards(cards.getCards(game), toZone, source, game);
}
@Override
public boolean moveCards(Set<Card> cards, Zone toZone, Ability source, Game game) {
public boolean moveCards(Set<Card> cards, Zone toZone,
Ability source, Game game
) {
return moveCards(cards, toZone, source, game, false, false, false, null);
}
@Override
public boolean moveCards(Set<Card> cards, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, List<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()) {
return true;
}
@ -3187,14 +3241,20 @@ public abstract class PlayerImpl implements Player, Serializable {
}
@Override
public boolean moveCardsToExile(Card card, Ability source, Game game, boolean withName, UUID exileId, String exileZoneName) {
public boolean moveCardsToExile(Card card, Ability source,
Game game, boolean withName, UUID exileId,
String exileZoneName
) {
Set<Card> cards = new HashSet<>();
cards.add(card);
return moveCardsToExile(cards, source, game, withName, exileId, exileZoneName);
}
@Override
public boolean moveCardsToExile(Set<Card> cards, Ability source, Game game, boolean withName, UUID exileId, String exileZoneName) {
public boolean moveCardsToExile(Set<Card> cards, Ability source,
Game game, boolean withName, UUID exileId,
String exileZoneName
) {
if (cards.isEmpty()) {
return true;
}
@ -3207,12 +3267,16 @@ public abstract class PlayerImpl implements Player, Serializable {
}
@Override
public boolean moveCardToHandWithInfo(Card card, UUID sourceId, Game game) {
public boolean moveCardToHandWithInfo(Card card, UUID sourceId,
Game game
) {
return this.moveCardToHandWithInfo(card, sourceId, game, true);
}
@Override
public boolean moveCardToHandWithInfo(Card card, UUID sourceId, Game game, boolean withName) {
public boolean moveCardToHandWithInfo(Card card, UUID sourceId,
Game game, boolean withName
) {
boolean result = false;
Zone fromZone = game.getState().getZone(card.getId());
if (fromZone == Zone.BATTLEFIELD && !(card instanceof Permanent)) {
@ -3235,7 +3299,9 @@ public abstract class PlayerImpl implements Player, Serializable {
}
@Override
public Set<Card> moveCardsToGraveyardWithInfo(Set<Card> allCards, Ability source, Game game, Zone fromZone) {
public Set<Card> moveCardsToGraveyardWithInfo(Set<Card> allCards, Ability source,
Game game, Zone fromZone
) {
UUID sourceId = source == null ? null : source.getSourceId();
Set<Card> movedCards = new LinkedHashSet<>();
while (!allCards.isEmpty()) {
@ -3302,7 +3368,9 @@ public abstract class PlayerImpl implements Player, Serializable {
}
@Override
public boolean moveCardToGraveyardWithInfo(Card card, UUID sourceId, Game game, Zone fromZone) {
public boolean moveCardToGraveyardWithInfo(Card card, UUID sourceId,
Game game, Zone fromZone
) {
if (card == null) {
return false;
}
@ -3329,7 +3397,10 @@ public abstract class PlayerImpl implements Player, Serializable {
}
@Override
public boolean moveCardToLibraryWithInfo(Card card, UUID sourceId, Game game, Zone fromZone, boolean toTop, boolean withName) {
public boolean moveCardToLibraryWithInfo(Card card, UUID sourceId,
Game game, Zone fromZone,
boolean toTop, boolean withName
) {
if (card == null) {
return false;
}
@ -3361,7 +3432,11 @@ public abstract class PlayerImpl implements Player, Serializable {
}
@Override
public boolean moveCardToExileWithInfo(Card card, UUID exileId, String exileName, UUID sourceId, Game game, Zone fromZone, boolean withName) {
public boolean moveCardToExileWithInfo(Card card, UUID exileId,
String exileName, UUID sourceId,
Game game, Zone fromZone,
boolean withName
) {
if (card == null) {
return false;
}
@ -3391,7 +3466,8 @@ public abstract class PlayerImpl implements Player, Serializable {
}
@Override
public boolean hasOpponent(UUID playerToCheckId, Game game) {
public boolean hasOpponent(UUID playerToCheckId, Game game
) {
return !this.getId().equals(playerToCheckId) && game.isOpponent(this, playerToCheckId);
}
@ -3436,7 +3512,8 @@ public abstract class PlayerImpl implements Player, Serializable {
}
@Override
public void setJustActivatedType(AbilityType justActivatedType) {
public void setJustActivatedType(AbilityType justActivatedType
) {
this.justActivatedType = justActivatedType;
}
@ -3446,7 +3523,8 @@ public abstract class PlayerImpl implements Player, Serializable {
}
@Override
public void addPermissionToShowHandCards(UUID watcherUserId) {
public void addPermissionToShowHandCards(UUID watcherUserId
) {
usersAllowedToSeeHandCards.add(watcherUserId);
}
@ -3456,7 +3534,8 @@ public abstract class PlayerImpl implements Player, Serializable {
}
@Override
public boolean hasUserPermissionToSeeHand(UUID userId) {
public boolean hasUserPermissionToSeeHand(UUID userId
) {
return usersAllowedToSeeHandCards.contains(userId);
}
@ -3466,7 +3545,8 @@ public abstract class PlayerImpl implements Player, Serializable {
}
@Override
public void setMatchPlayer(MatchPlayer matchPlayer) {
public void setMatchPlayer(MatchPlayer matchPlayer
) {
this.matchPlayer = matchPlayer;
}
@ -3481,7 +3561,9 @@ public abstract class PlayerImpl implements Player, Serializable {
}
@Override
public boolean scry(int value, Ability source, Game game) {
public boolean scry(int value, Ability source,
Game game
) {
game.informPlayers(getLogName() + " scries " + value);
Cards cards = new CardsImpl();
cards.addAll(getLibrary().getTopCards(game, value));
@ -3503,7 +3585,8 @@ public abstract class PlayerImpl implements Player, Serializable {
}
@Override
public boolean addTargets(Ability ability, Game game) {
public boolean addTargets(Ability ability, Game game
) {
// only used for TestPlayer to preSet Targets
return true;
}