mirror of
https://github.com/magefree/mage.git
synced 2025-12-20 02:30:08 -08:00
reworked AI, targeting and targets logic:
- refactor: simplified target implementation from a dozen canTarget, canChoose and possibleTargets methods to canTarget/possibleTargets only (part of #13638, #13766); - refactor: fixed wrong target implementations in many cards (example: TargetCardInHand for opponent's hand, close #6210); - AI: now human, AI and test players -- all use possibleTargets logic in most use cases instead filters or custom validation; - AI: improved AI sims support for multiple targets abilities; - AI: improved AI stability, freezes and targets errors in some use cases;
This commit is contained in:
parent
e866707912
commit
c7a485b728
240 changed files with 1652 additions and 3096 deletions
|
|
@ -18,10 +18,8 @@ import javax.swing.*;
|
|||
import java.awt.*;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
|
|
@ -258,7 +256,7 @@ public class CardArea extends JPanel implements CardEventProducer {
|
|||
this.reloaded = false;
|
||||
}
|
||||
|
||||
public void selectCards(List<UUID> selected) {
|
||||
public void selectCards(Set<UUID> selected) {
|
||||
for (Component component : cardArea.getComponents()) {
|
||||
if (component instanceof MageCard) {
|
||||
MageCard mageCard = (MageCard) component;
|
||||
|
|
@ -269,7 +267,7 @@ public class CardArea extends JPanel implements CardEventProducer {
|
|||
}
|
||||
}
|
||||
|
||||
public void markCards(List<UUID> marked) {
|
||||
public void markCards(Set<UUID> marked) {
|
||||
for (Component component : cardArea.getComponents()) {
|
||||
if (component instanceof MageCard) {
|
||||
MageCard mageCard = (MageCard) component;
|
||||
|
|
|
|||
|
|
@ -100,11 +100,11 @@
|
|||
cardArea.loadCards(showCards, bigCard, gameId);
|
||||
if (options != null) {
|
||||
if (options.containsKey("chosenTargets")) {
|
||||
java.util.List<UUID> chosenCards = (java.util.List<UUID>) options.get("chosenTargets");
|
||||
java.util.Set<UUID> chosenCards = (java.util.Set<UUID>) options.get("chosenTargets");
|
||||
cardArea.selectCards(chosenCards);
|
||||
}
|
||||
if (options.containsKey("possibleTargets")) {
|
||||
java.util.List<UUID> choosableCards = (java.util.List<UUID>) options.get("possibleTargets");
|
||||
java.util.Set<UUID> choosableCards = (java.util.Set<UUID>) options.get("possibleTargets");
|
||||
cardArea.markCards(choosableCards);
|
||||
}
|
||||
if (options.containsKey("queryType") && options.get("queryType") == QueryType.PICK_ABILITY) {
|
||||
|
|
|
|||
|
|
@ -216,17 +216,9 @@ public final class GamePanel extends javax.swing.JPanel {
|
|||
});
|
||||
}
|
||||
|
||||
public List<UUID> getPossibleTargets() {
|
||||
if (options != null && options.containsKey("possibleTargets")) {
|
||||
return (List<UUID>) options.get("possibleTargets");
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
public Set<UUID> getChosenTargets() {
|
||||
if (options != null && options.containsKey("chosenTargets")) {
|
||||
return new HashSet<>((List<UUID>) options.get("chosenTargets"));
|
||||
return (Set<UUID>) options.get("chosenTargets");
|
||||
} else {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package mage.player.human;
|
|||
import mage.MageIdentifier;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.*;
|
||||
import mage.abilities.costs.VariableCost;
|
||||
import mage.abilities.costs.common.SacrificeSourceCost;
|
||||
import mage.abilities.costs.common.TapSourceCost;
|
||||
import mage.abilities.costs.mana.ManaCost;
|
||||
|
|
@ -697,7 +696,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
}
|
||||
|
||||
// stop on completed, e.g. X=0
|
||||
if (target.isChoiceCompleted(abilityControllerId, source, game)) {
|
||||
if (target.isChoiceCompleted(abilityControllerId, source, game, null)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -729,7 +728,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
// continue to next target (example: auto-choose must fill min/max = 2 from 2 possible cards)
|
||||
} else {
|
||||
// manual choose
|
||||
options.put("chosenTargets", (Serializable) target.getTargets());
|
||||
options.put("chosenTargets", new HashSet<>(target.getTargets()));
|
||||
|
||||
prepareForResponse(game);
|
||||
if (!isExecutingMacro()) {
|
||||
|
|
@ -747,9 +746,9 @@ public class HumanPlayer extends PlayerImpl {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (possibleTargets.contains(responseId) && target.canTarget(getId(), responseId, source, game)) {
|
||||
if (possibleTargets.contains(responseId)) {
|
||||
target.add(responseId, game);
|
||||
if (target.isChoiceCompleted(abilityControllerId, source, game)) {
|
||||
if (target.isChoiceCompleted(abilityControllerId, source, game, null)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -794,7 +793,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
|
||||
// manual choice
|
||||
if (responseId == null) {
|
||||
options.put("chosenTargets", (Serializable) target.getTargets());
|
||||
options.put("chosenTargets", new HashSet<>(target.getTargets()));
|
||||
|
||||
prepareForResponse(game);
|
||||
if (!isExecutingMacro()) {
|
||||
|
|
@ -814,11 +813,9 @@ public class HumanPlayer extends PlayerImpl {
|
|||
|
||||
// add new target
|
||||
if (possibleTargets.contains(responseId)) {
|
||||
if (target.canTarget(abilityControllerId, responseId, source, game)) {
|
||||
target.addTarget(responseId, source, game);
|
||||
if (target.isChoiceCompleted(abilityControllerId, source, game)) {
|
||||
return true;
|
||||
}
|
||||
target.addTarget(responseId, source, game);
|
||||
if (target.isChoiceCompleted(abilityControllerId, source, game, null)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -864,13 +861,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
UUID abilityControllerId = target.getAffectedAbilityControllerId(this.getId());
|
||||
|
||||
while (canRespond()) {
|
||||
|
||||
List<UUID> possibleTargets = new ArrayList<>();
|
||||
for (UUID cardId : cards) {
|
||||
if (target.canTarget(abilityControllerId, cardId, source, cards, game)) {
|
||||
possibleTargets.add(cardId);
|
||||
}
|
||||
}
|
||||
Set<UUID> possibleTargets = target.possibleTargets(abilityControllerId, source, game, cards);
|
||||
|
||||
boolean required = target.isRequired(source != null ? source.getSourceId() : null, game);
|
||||
int count = cards.count(target.getFilter(), abilityControllerId, source, game);
|
||||
|
|
@ -880,7 +871,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
}
|
||||
|
||||
// if nothing to choose then show dialog (user must see non selectable items and click on any of them)
|
||||
// TODO: need research - is it used?
|
||||
// TODO: need research - is it used (test player and AI player don't see empty dialogs)?
|
||||
if (required && possibleTargets.isEmpty()) {
|
||||
required = false;
|
||||
}
|
||||
|
|
@ -894,7 +885,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
} else {
|
||||
// manual choose
|
||||
Map<String, Serializable> options = getOptions(target, null);
|
||||
options.put("chosenTargets", (Serializable) target.getTargets());
|
||||
options.put("chosenTargets", new HashSet<>(target.getTargets()));
|
||||
if (!possibleTargets.isEmpty()) {
|
||||
options.put("possibleTargets", (Serializable) possibleTargets);
|
||||
}
|
||||
|
|
@ -916,9 +907,9 @@ public class HumanPlayer extends PlayerImpl {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (possibleTargets.contains(responseId) && target.canTarget(getId(), responseId, source, cards, game)) {
|
||||
if (possibleTargets.contains(responseId)) {
|
||||
target.add(responseId, game);
|
||||
if (target.isChoiceCompleted(abilityControllerId, source, game)) {
|
||||
if (target.isChoiceCompleted(abilityControllerId, source, game, cards)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -962,12 +953,8 @@ public class HumanPlayer extends PlayerImpl {
|
|||
required = false;
|
||||
}
|
||||
|
||||
List<UUID> possibleTargets = new ArrayList<>();
|
||||
for (UUID cardId : cards) {
|
||||
if (target.canTarget(abilityControllerId, cardId, source, cards, game)) {
|
||||
possibleTargets.add(cardId);
|
||||
}
|
||||
}
|
||||
Set<UUID> possibleTargets = target.possibleTargets(abilityControllerId, source, game, cards);
|
||||
|
||||
// if nothing to choose then show dialog (user must see non-selectable items and click on any of them)
|
||||
if (possibleTargets.isEmpty()) {
|
||||
required = false;
|
||||
|
|
@ -977,7 +964,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
|
||||
if (responseId == null) {
|
||||
Map<String, Serializable> options = getOptions(target, null);
|
||||
options.put("chosenTargets", (Serializable) target.getTargets());
|
||||
options.put("chosenTargets", new HashSet<>(target.getTargets()));
|
||||
|
||||
if (!possibleTargets.isEmpty()) {
|
||||
options.put("possibleTargets", (Serializable) possibleTargets);
|
||||
|
|
@ -995,9 +982,9 @@ public class HumanPlayer extends PlayerImpl {
|
|||
if (responseId != null) {
|
||||
if (target.contains(responseId)) { // if already included remove it
|
||||
target.remove(responseId);
|
||||
} else if (target.canTarget(abilityControllerId, responseId, source, cards, game)) {
|
||||
} else if (possibleTargets.contains(responseId)) {
|
||||
target.addTarget(responseId, source, game);
|
||||
if (target.isChoiceCompleted(abilityControllerId, source, game)) {
|
||||
if (target.isChoiceCompleted(abilityControllerId, source, game, cards)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1054,9 +1041,9 @@ public class HumanPlayer extends PlayerImpl {
|
|||
// 1. Select targets
|
||||
// TODO: rework to use existing chooseTarget instead custom select?
|
||||
while (canRespond()) {
|
||||
Set<UUID> possibleTargetIds = target.possibleTargets(abilityControllerId, source, game);
|
||||
Set<UUID> possibleTargets = target.possibleTargets(abilityControllerId, source, game);
|
||||
boolean required = target.isRequired(source.getSourceId(), game);
|
||||
if (possibleTargetIds.isEmpty()
|
||||
if (possibleTargets.isEmpty()
|
||||
|| target.getSize() >= target.getMinNumberOfTargets()) {
|
||||
required = false;
|
||||
}
|
||||
|
|
@ -1065,12 +1052,6 @@ public class HumanPlayer extends PlayerImpl {
|
|||
|
||||
// responseId is null if a choice couldn't be automatically made
|
||||
if (responseId == null) {
|
||||
List<UUID> possibleTargets = new ArrayList<>();
|
||||
for (UUID targetId : possibleTargetIds) {
|
||||
if (target.canTarget(abilityControllerId, targetId, source, game)) {
|
||||
possibleTargets.add(targetId);
|
||||
}
|
||||
}
|
||||
// if nothing to choose then show dialog (user must see non selectable items and click on any of them)
|
||||
if (required && possibleTargets.isEmpty()) {
|
||||
required = false;
|
||||
|
|
@ -1078,7 +1059,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
|
||||
// selected
|
||||
Map<String, Serializable> options = getOptions(target, null);
|
||||
options.put("chosenTargets", (Serializable) target.getTargets());
|
||||
options.put("chosenTargets", new HashSet<>(target.getTargets()));
|
||||
if (!possibleTargets.isEmpty()) {
|
||||
options.put("possibleTargets", (Serializable) possibleTargets);
|
||||
}
|
||||
|
|
@ -1087,7 +1068,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
if (!isExecutingMacro()) {
|
||||
String multiType = multiAmountType == MultiAmountType.DAMAGE ? " to divide %d damage" : " to distribute %d counters";
|
||||
String message = target.getMessage(game) + String.format(multiType, amountTotal);
|
||||
game.fireSelectTargetEvent(playerId, new MessageToClient(message, getRelatedObjectName(source, game)), possibleTargetIds, required, options);
|
||||
game.fireSelectTargetEvent(playerId, new MessageToClient(message, getRelatedObjectName(source, game)), possibleTargets, required, options);
|
||||
}
|
||||
waitForResponse(game);
|
||||
|
||||
|
|
@ -1098,9 +1079,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
if (target.contains(responseId)) {
|
||||
// unselect
|
||||
target.remove(responseId);
|
||||
} else if (possibleTargetIds.contains(responseId)
|
||||
&& target.canTarget(abilityControllerId, responseId, source, game)
|
||||
&& target.getSize() < amountTotal) {
|
||||
} else if (possibleTargets.contains(responseId) && target.getSize() < amountTotal) {
|
||||
// select
|
||||
target.addTarget(responseId, source, game);
|
||||
}
|
||||
|
|
@ -2094,32 +2073,33 @@ public class HumanPlayer extends PlayerImpl {
|
|||
if (!canCallFeedback(game)) {
|
||||
return;
|
||||
}
|
||||
TargetAttackingCreature target = new TargetAttackingCreature();
|
||||
|
||||
// TODO: add canRespond cycle?
|
||||
// no need in cycle, cause parent selectBlockers used it already
|
||||
if (!canRespond()) {
|
||||
return;
|
||||
}
|
||||
|
||||
UUID responseId = null;
|
||||
|
||||
prepareForResponse(game);
|
||||
if (!isExecutingMacro()) {
|
||||
// possible attackers to block
|
||||
Set<UUID> attackers = target.possibleTargets(playerId, null, game);
|
||||
TargetAttackingCreature target = new TargetAttackingCreature();
|
||||
Permanent blocker = game.getPermanent(blockerId);
|
||||
Set<UUID> possibleTargets = new HashSet<>();
|
||||
for (UUID attackerId : attackers) {
|
||||
Set<UUID> allAttackers = target.possibleTargets(playerId, null, game);
|
||||
Set<UUID> possibleAttackersToBlock = new HashSet<>();
|
||||
for (UUID attackerId : allAttackers) {
|
||||
CombatGroup group = game.getCombat().findGroup(attackerId);
|
||||
if (group != null && blocker != null && group.canBlock(blocker, game)) {
|
||||
possibleTargets.add(attackerId);
|
||||
possibleAttackersToBlock.add(attackerId);
|
||||
}
|
||||
}
|
||||
if (possibleTargets.size() == 1) {
|
||||
responseId = possibleTargets.stream().iterator().next();
|
||||
if (possibleAttackersToBlock.size() == 1) {
|
||||
// auto-choice
|
||||
responseId = possibleAttackersToBlock.stream().iterator().next();
|
||||
} else {
|
||||
prepareForResponse(game);
|
||||
game.fireSelectTargetEvent(playerId, new MessageToClient("Select attacker to block", getRelatedObjectName(blockerId, game)),
|
||||
possibleTargets, false, getOptions(target, null));
|
||||
possibleAttackersToBlock, false, getOptions(target, null));
|
||||
waitForResponse(game);
|
||||
}
|
||||
}
|
||||
|
|
@ -2174,7 +2154,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
break;
|
||||
}
|
||||
|
||||
return xValue;
|
||||
return xValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ class AjanisChosenEffect extends OneShotEffect {
|
|||
Permanent oldCreature = game.getPermanent(enchantment.getAttachedTo());
|
||||
if (oldCreature != null) {
|
||||
boolean canAttach = enchantment.getSpellAbility() == null
|
||||
|| (!enchantment.getSpellAbility().getTargets().isEmpty() && enchantment.getSpellAbility().getTargets().get(0).canTarget(tokenPermanent.getId(), game));
|
||||
|| (!enchantment.getSpellAbility().getTargets().isEmpty() && enchantment.getSpellAbility().getTargets().get(0).canTarget(tokenPermanent.getId(), source, game));
|
||||
if (canAttach && controller.chooseUse(Outcome.Neutral, "Attach " + enchantment.getName() + " to the token ?", source, game)) {
|
||||
if (oldCreature.removeAttachment(enchantment.getId(), source, game)) {
|
||||
tokenPermanent.addAttachment(enchantment.getId(), source, game);
|
||||
|
|
|
|||
|
|
@ -108,8 +108,8 @@ class AncientBrassDragonTarget extends TargetCardInGraveyard {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) {
|
||||
return super.canTarget(controllerId, id, source, game)
|
||||
public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) {
|
||||
return super.canTarget(playerId, id, source, game)
|
||||
&& CardUtil.checkCanTargetTotalValueLimit(
|
||||
this.getTargets(), id, MageObject::getManaValue, xValue, game);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ class AnuridScavengerCost extends CostImpl {
|
|||
|
||||
@Override
|
||||
public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) {
|
||||
return this.getTargets().canChoose(controllerId, source, game);
|
||||
return canChooseOrAlreadyChosen(ability, source, controllerId, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -134,8 +134,8 @@ class AoTheDawnSkyTarget extends TargetCardInLibrary {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) {
|
||||
return super.canTarget(controllerId, id, source, game)
|
||||
public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) {
|
||||
return super.canTarget(playerId, id, source, game)
|
||||
&& CardUtil.checkCanTargetTotalValueLimit(
|
||||
this.getTargets(), id, MageObject::getManaValue, 4, game);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ class ArdentDustspeakerCost extends CostImpl {
|
|||
|
||||
@Override
|
||||
public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) {
|
||||
return this.getTargets().canChoose(controllerId, source, game);
|
||||
return canChooseOrAlreadyChosen(ability, source, controllerId, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ class BackFromTheBrinkCost extends CostImpl {
|
|||
|
||||
@Override
|
||||
public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) {
|
||||
return this.getTargets().canChoose(controllerId, source, game);
|
||||
return canChooseOrAlreadyChosen(ability, source, controllerId, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -147,6 +147,7 @@ class BattleForBretagardTarget extends TargetPermanent {
|
|||
@Override
|
||||
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
|
||||
Set<UUID> possibleTargets = super.possibleTargets(sourceControllerId, source, game);
|
||||
|
||||
Set<String> names = this.getTargets()
|
||||
.stream()
|
||||
.map(game::getPermanent)
|
||||
|
|
@ -159,6 +160,7 @@ class BattleForBretagardTarget extends TargetPermanent {
|
|||
Permanent permanent = game.getPermanent(uuid);
|
||||
return permanent == null || names.contains(permanent.getName());
|
||||
});
|
||||
|
||||
return possibleTargets;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ class BattlefieldScroungerCost extends CostImpl {
|
|||
|
||||
@Override
|
||||
public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) {
|
||||
return this.getTargets().canChoose(controllerId, source, game);
|
||||
return canChooseOrAlreadyChosen(ability, source, controllerId, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -66,12 +66,12 @@ class BeguilerOfWillsTarget extends TargetPermanent {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) {
|
||||
public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) {
|
||||
Permanent permanent = game.getPermanent(id);
|
||||
int count = game.getBattlefield().countAll(this.filter, source.getControllerId(), game);
|
||||
|
||||
if (permanent != null && permanent.getPower().getValue() <= count) {
|
||||
return super.canTarget(controllerId, id, source, game);
|
||||
return super.canTarget(playerId, id, source, game);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,18 +49,18 @@ class BlazingHopeTarget extends TargetPermanent {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) {
|
||||
public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) {
|
||||
Permanent permanent = game.getPermanent(id);
|
||||
if (permanent != null) {
|
||||
if (!isNotTarget()) {
|
||||
if (!permanent.canBeTargetedBy(game.getObject(source.getId()), controllerId, source, game)
|
||||
|| !permanent.canBeTargetedBy(game.getObject(source), controllerId, source, game)) {
|
||||
if (!permanent.canBeTargetedBy(game.getObject(source.getId()), playerId, source, game)
|
||||
|| !permanent.canBeTargetedBy(game.getObject(source), playerId, source, game)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null && permanent.getPower().getValue() >= controller.getLife()) {
|
||||
return filter.match(permanent, controllerId, source, game);
|
||||
return filter.match(permanent, playerId, source, game);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package mage.cards.b;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.keyword.TheRingTemptsYouEffect;
|
||||
|
|
@ -8,20 +7,20 @@ import mage.cards.CardImpl;
|
|||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.filter.predicate.Predicates;
|
||||
import mage.filter.predicate.permanent.ControllerIdPredicate;
|
||||
import mage.filter.predicate.permanent.PermanentIdPredicate;
|
||||
import mage.filter.common.FilterOpponentsCreaturePermanent;
|
||||
import mage.filter.predicate.mageobject.AnotherPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.target.TargetPermanent;
|
||||
import mage.target.common.TargetCreaturePermanent;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* TODO: combine with Mutiny
|
||||
*
|
||||
* @author Susucr
|
||||
*/
|
||||
public final class BreakingOfTheFellowship extends CardImpl {
|
||||
|
|
@ -31,8 +30,8 @@ public final class BreakingOfTheFellowship extends CardImpl {
|
|||
|
||||
// Target creature an opponent controls deals damage equal to its power to another target creature that player controls.
|
||||
this.getSpellAbility().addEffect(new BreakingOfTheFellowshipEffect());
|
||||
this.getSpellAbility().addTarget(new BreakingOfTheFellowshipFirstTarget());
|
||||
this.getSpellAbility().addTarget(new TargetPermanent(new FilterCreaturePermanent("another target creature that player controls")));
|
||||
this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE));
|
||||
this.getSpellAbility().addTarget(new BreakingOfTheFellowshipSecondTarget());
|
||||
|
||||
// The Ring tempts you.
|
||||
this.getSpellAbility().addEffect(new TheRingTemptsYouEffect());
|
||||
|
|
@ -76,74 +75,45 @@ class BreakingOfTheFellowshipEffect extends OneShotEffect {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class BreakingOfTheFellowshipFirstTarget extends TargetPermanent {
|
||||
class BreakingOfTheFellowshipSecondTarget extends TargetPermanent {
|
||||
|
||||
public BreakingOfTheFellowshipFirstTarget() {
|
||||
super(1, 1, StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE, false);
|
||||
public BreakingOfTheFellowshipSecondTarget() {
|
||||
super(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE);
|
||||
}
|
||||
|
||||
private BreakingOfTheFellowshipFirstTarget(final BreakingOfTheFellowshipFirstTarget target) {
|
||||
private BreakingOfTheFellowshipSecondTarget(final BreakingOfTheFellowshipSecondTarget target) {
|
||||
super(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTarget(UUID id, Ability source, Game game, boolean skipEvent) {
|
||||
super.addTarget(id, source, game, skipEvent);
|
||||
// Update the second target
|
||||
UUID firstController = game.getControllerId(id);
|
||||
if (firstController != null && source.getTargets().size() > 1) {
|
||||
Player controllingPlayer = game.getPlayer(firstController);
|
||||
TargetCreaturePermanent targetCreaturePermanent = (TargetCreaturePermanent) source.getTargets().get(1);
|
||||
// Set a new filter to the second target with the needed restrictions
|
||||
FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature that player " + controllingPlayer.getName() + " controls");
|
||||
filter.add(new ControllerIdPredicate(firstController));
|
||||
filter.add(Predicates.not(new PermanentIdPredicate(id)));
|
||||
targetCreaturePermanent.replaceFilter(filter);
|
||||
}
|
||||
}
|
||||
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
|
||||
Set<UUID> possibleTargets = super.possibleTargets(sourceControllerId, source, game);
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) {
|
||||
if (super.canTarget(controllerId, id, source, game)) {
|
||||
// can only target, if the controller has at least two targetable creatures
|
||||
UUID controllingPlayerId = game.getControllerId(id);
|
||||
int possibleTargets = 0;
|
||||
MageObject sourceObject = game.getObject(source.getId());
|
||||
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, controllingPlayerId, game)) {
|
||||
if (permanent.canBeTargetedBy(sourceObject, controllerId, source, game)) {
|
||||
possibleTargets++;
|
||||
}
|
||||
Permanent firstTarget = game.getPermanent(source.getFirstTarget());
|
||||
if (firstTarget == null) {
|
||||
// playable or first target not yet selected
|
||||
// use all
|
||||
if (possibleTargets.size() == 1) {
|
||||
// workaround to make 1 target invalid
|
||||
possibleTargets.clear();
|
||||
}
|
||||
return possibleTargets > 1;
|
||||
} else {
|
||||
// real
|
||||
// filter by same player
|
||||
possibleTargets.removeIf(id -> {
|
||||
Permanent permanent = game.getPermanent(id);
|
||||
return permanent == null || !permanent.isControlledBy(firstTarget.getControllerId());
|
||||
});
|
||||
}
|
||||
return false;
|
||||
possibleTargets.removeIf(id -> firstTarget != null && firstTarget.getId().equals(id));
|
||||
|
||||
return possibleTargets;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canChoose(UUID sourceControllerId, Ability source, Game game) {
|
||||
if (super.canChoose(sourceControllerId, source, game)) {
|
||||
UUID controllingPlayerId = game.getControllerId(source.getSourceId());
|
||||
for (UUID playerId : game.getOpponents(controllingPlayerId)) {
|
||||
int possibleTargets = 0;
|
||||
MageObject sourceObject = game.getObject(source);
|
||||
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, playerId, game)) {
|
||||
if (permanent.canBeTargetedBy(sourceObject, controllingPlayerId, source, game)) {
|
||||
possibleTargets++;
|
||||
}
|
||||
}
|
||||
if (possibleTargets > 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BreakingOfTheFellowshipFirstTarget copy() {
|
||||
return new BreakingOfTheFellowshipFirstTarget(this);
|
||||
public BreakingOfTheFellowshipSecondTarget copy() {
|
||||
return new BreakingOfTheFellowshipSecondTarget(this);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,8 +141,8 @@ class CallOfTheDeathDwellerTarget extends TargetCardInYourGraveyard {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) {
|
||||
return super.canTarget(controllerId, id, source, game)
|
||||
public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) {
|
||||
return super.canTarget(playerId, id, source, game)
|
||||
&& CardUtil.checkCanTargetTotalValueLimit(
|
||||
this.getTargets(), id, MageObject::getManaValue, 3, game);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
package mage.cards.c;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import mage.ApprovingObject;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
|
|
@ -17,7 +14,6 @@ import mage.filter.common.FilterCreaturePermanent;
|
|||
import mage.filter.common.FilterInstantOrSorceryCard;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.stack.StackObject;
|
||||
import mage.players.Player;
|
||||
import mage.target.Target;
|
||||
import mage.target.TargetCard;
|
||||
|
|
@ -25,6 +21,9 @@ import mage.target.TargetPermanent;
|
|||
import mage.target.common.TargetPlayerOrPlaneswalker;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author jeffwadsworth
|
||||
*/
|
||||
|
|
@ -111,47 +110,23 @@ class ChandraPyromasterTarget extends TargetPermanent {
|
|||
super(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID id, Ability source, Game game) {
|
||||
Player player = game.getPlayerOrPlaneswalkerController(source.getFirstTarget());
|
||||
if (player == null) {
|
||||
return false;
|
||||
}
|
||||
UUID firstTarget = player.getId();
|
||||
Permanent permanent = game.getPermanent(id);
|
||||
if (firstTarget != null && permanent != null && permanent.isControlledBy(firstTarget)) {
|
||||
return super.canTarget(id, source, game);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
|
||||
Set<UUID> availablePossibleTargets = super.possibleTargets(sourceControllerId, source, game);
|
||||
Set<UUID> possibleTargets = new HashSet<>();
|
||||
MageObject object = game.getObject(source);
|
||||
Set<UUID> possibleTargets = super.possibleTargets(sourceControllerId, source, game);
|
||||
|
||||
for (StackObject item : game.getState().getStack()) {
|
||||
if (item.getId().equals(source.getSourceId())) {
|
||||
object = item;
|
||||
}
|
||||
if (item.getSourceId().equals(source.getSourceId())) {
|
||||
object = item;
|
||||
}
|
||||
Player needPlayer = game.getPlayerOrPlaneswalkerController(source.getFirstTarget());
|
||||
if (needPlayer == null) {
|
||||
// playable or not selected - use any
|
||||
} else {
|
||||
// filter by controller
|
||||
possibleTargets.removeIf(id -> {
|
||||
Permanent permanent = game.getPermanent(id);
|
||||
return permanent == null
|
||||
|| permanent.getId().equals(source.getFirstTarget())
|
||||
|| !permanent.isControlledBy(needPlayer.getId());
|
||||
});
|
||||
}
|
||||
|
||||
if (object instanceof StackObject) {
|
||||
UUID playerId = ((StackObject) object).getStackAbility().getFirstTarget();
|
||||
Player player = game.getPlayerOrPlaneswalkerController(playerId);
|
||||
if (player != null) {
|
||||
for (UUID targetId : availablePossibleTargets) {
|
||||
Permanent permanent = game.getPermanent(targetId);
|
||||
if (permanent != null && permanent.isControlledBy(player.getId())) {
|
||||
possibleTargets.add(targetId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return possibleTargets;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -124,8 +124,8 @@ class ChaosMutationTarget extends TargetPermanent {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) {
|
||||
if (!super.canTarget(controllerId, id, source, game)) {
|
||||
public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) {
|
||||
if (!super.canTarget(playerId, id, source, game)) {
|
||||
return false;
|
||||
}
|
||||
Permanent creature = game.getPermanent(id);
|
||||
|
|
|
|||
|
|
@ -85,8 +85,8 @@ class CloudsLimitBreakTarget extends TargetPermanent {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) {
|
||||
if (!super.canTarget(controllerId, id, source, game)) {
|
||||
public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) {
|
||||
if (!super.canTarget(playerId, id, source, game)) {
|
||||
return false;
|
||||
}
|
||||
Permanent creature = game.getPermanent(id);
|
||||
|
|
|
|||
|
|
@ -119,8 +119,7 @@ class ConspiracyTheoristEffect extends OneShotEffect {
|
|||
if (controller != null) {
|
||||
CardsImpl cards = new CardsImpl(discardedCards);
|
||||
TargetCard target = new TargetCard(Zone.GRAVEYARD, new FilterCard("card to exile"));
|
||||
boolean validTarget = cards.stream()
|
||||
.anyMatch(card -> target.canTarget(card, game));
|
||||
boolean validTarget = cards.stream().anyMatch(card -> target.canTarget(card, source, game));
|
||||
if (validTarget && controller.chooseUse(Outcome.Benefit, "Exile a card?", source, game)) {
|
||||
if (controller.choose(Outcome.Benefit, cards, target, source, game)) {
|
||||
Card card = cards.get(target.getFirstTarget(), game);
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import mage.abilities.keyword.InspiredAbility;
|
|||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.*;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.filter.predicate.Predicates;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
|
@ -35,8 +36,12 @@ public final class DaringThief extends CardImpl {
|
|||
this.toughness = new MageInt(3);
|
||||
|
||||
// Inspired - Whenever Daring Thief becomes untapped, you may exchange control of target nonland permanent you control and target permanent an opponent controls that shares a card type with it.
|
||||
Ability ability = new InspiredAbility(new ExchangeControlTargetEffect(Duration.EndOfGame,
|
||||
"you may exchange control of target nonland permanent you control and target permanent an opponent controls that shares a card type with it", false, true), true);
|
||||
Ability ability = new InspiredAbility(new ExchangeControlTargetEffect(
|
||||
Duration.EndOfGame,
|
||||
"you may exchange control of target nonland permanent you control and target permanent an opponent controls that shares a card type with it",
|
||||
false,
|
||||
true
|
||||
), true);
|
||||
ability.addTarget(new TargetControlledPermanentSharingOpponentPermanentCardType());
|
||||
ability.addTarget(new DaringThiefSecondTarget());
|
||||
this.addAbility(ability);
|
||||
|
|
@ -66,9 +71,10 @@ class TargetControlledPermanentSharingOpponentPermanentCardType extends TargetCo
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) {
|
||||
if (super.canTarget(controllerId, id, source, game)) {
|
||||
Set<CardType> cardTypes = getOpponentPermanentCardTypes(controllerId, game);
|
||||
public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) {
|
||||
Set<CardType> cardTypes = getOpponentPermanentCardTypes(playerId, game);
|
||||
|
||||
if (super.canTarget(playerId, id, source, game)) {
|
||||
Permanent permanent = game.getPermanent(id);
|
||||
for (CardType type : permanent.getCardType(game)) {
|
||||
if (cardTypes.contains(type)) {
|
||||
|
|
@ -81,23 +87,21 @@ class TargetControlledPermanentSharingOpponentPermanentCardType extends TargetCo
|
|||
|
||||
@Override
|
||||
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
|
||||
// get all cardtypes from opponents permanents
|
||||
Set<CardType> cardTypes = getOpponentPermanentCardTypes(sourceControllerId, game);
|
||||
|
||||
Set<UUID> possibleTargets = new HashSet<>();
|
||||
MageObject targetSource = game.getObject(source);
|
||||
if (targetSource != null) {
|
||||
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) {
|
||||
if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, source, game)) {
|
||||
for (CardType type : permanent.getCardType(game)) {
|
||||
if (cardTypes.contains(type)) {
|
||||
possibleTargets.add(permanent.getId());
|
||||
break;
|
||||
}
|
||||
for (CardType type : permanent.getCardType(game)) {
|
||||
if (cardTypes.contains(type)) {
|
||||
possibleTargets.add(permanent.getId());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return possibleTargets;
|
||||
return keepValidPossibleTargets(possibleTargets, sourceControllerId, source, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -119,58 +123,54 @@ class TargetControlledPermanentSharingOpponentPermanentCardType extends TargetCo
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
class DaringThiefSecondTarget extends TargetPermanent {
|
||||
|
||||
private Permanent firstTarget = null;
|
||||
|
||||
public DaringThiefSecondTarget() {
|
||||
super();
|
||||
this.filter = this.filter.copy();
|
||||
filter.add(TargetController.OPPONENT.getControllerPredicate());
|
||||
super(StaticFilters.FILTER_OPPONENTS_PERMANENT);
|
||||
withTargetName("permanent an opponent controls that shares a card type with it");
|
||||
}
|
||||
|
||||
private DaringThiefSecondTarget(final DaringThiefSecondTarget target) {
|
||||
super(target);
|
||||
this.firstTarget = target.firstTarget;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID id, Ability source, Game game) {
|
||||
if (super.canTarget(id, source, game)) {
|
||||
Permanent target1 = game.getPermanent(source.getFirstTarget());
|
||||
Permanent opponentPermanent = game.getPermanent(id);
|
||||
if (target1 != null && opponentPermanent != null) {
|
||||
return target1.shareTypes(opponentPermanent, game);
|
||||
}
|
||||
Permanent ownPermanent = game.getPermanent(source.getFirstTarget());
|
||||
Permanent possiblePermanent = game.getPermanent(id);
|
||||
if (ownPermanent == null || possiblePermanent == null) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
return super.canTarget(id, source, game) && ownPermanent.shareTypes(possiblePermanent, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
|
||||
Set<UUID> possibleTargets = new HashSet<>();
|
||||
if (firstTarget != null) {
|
||||
MageObject targetSource = game.getObject(source);
|
||||
if (targetSource != null) {
|
||||
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) {
|
||||
if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, source, game)) {
|
||||
if (permanent.shareTypes(firstTarget, game)) {
|
||||
possibleTargets.add(permanent.getId());
|
||||
}
|
||||
}
|
||||
|
||||
Permanent ownPermanent = game.getPermanent(source.getFirstTarget());
|
||||
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) {
|
||||
if (ownPermanent == null) {
|
||||
// playable or first target not yet selected
|
||||
// use all
|
||||
possibleTargets.add(permanent.getId());
|
||||
} else {
|
||||
// real
|
||||
// filter by shared type
|
||||
if (permanent.shareTypes(ownPermanent, game)) {
|
||||
possibleTargets.add(permanent.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
return possibleTargets;
|
||||
possibleTargets.removeIf(id -> ownPermanent != null && ownPermanent.getId().equals(id));
|
||||
|
||||
return keepValidPossibleTargets(possibleTargets, sourceControllerId, source, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean chooseTarget(Outcome outcome, UUID playerId, Ability source, Game game) {
|
||||
firstTarget = game.getPermanent(source.getFirstTarget());
|
||||
return super.chooseTarget(Outcome.Damage, playerId, source, game);
|
||||
// AI hint with better outcome
|
||||
return super.chooseTarget(Outcome.GainControl, playerId, source, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -91,9 +91,7 @@ class DeepCaverBatEffect extends OneShotEffect {
|
|||
return true;
|
||||
}
|
||||
|
||||
TargetCard target = new TargetCardInHand(
|
||||
0, 1, StaticFilters.FILTER_CARD_A_NON_LAND
|
||||
);
|
||||
TargetCard target = new TargetCard(0, 1, Zone.HAND, StaticFilters.FILTER_CARD_A_NON_LAND);
|
||||
controller.choose(outcome, opponent.getHand(), target, source, game);
|
||||
Card card = opponent.getHand().get(target.getFirstTarget(), game);
|
||||
if (card == null) {
|
||||
|
|
|
|||
|
|
@ -137,49 +137,12 @@ class TargetControlledSource extends TargetSource {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canChoose(UUID sourceControllerId, Game game) {
|
||||
int count = 0;
|
||||
for (StackObject stackObject : game.getStack()) {
|
||||
if (game.getState().getPlayersInRange(sourceControllerId, game).contains(stackObject.getControllerId())
|
||||
&& Objects.equals(stackObject.getControllerId(), sourceControllerId)) {
|
||||
count++;
|
||||
if (count >= this.minNumberOfTargets) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Permanent permanent : game.getBattlefield().getActivePermanents(sourceControllerId, game)) {
|
||||
if (Objects.equals(permanent.getControllerId(), sourceControllerId)) {
|
||||
count++;
|
||||
if (count >= this.minNumberOfTargets) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Player player : game.getPlayers().values()) {
|
||||
if (Objects.equals(player, game.getPlayer(sourceControllerId))) {
|
||||
for (Card card : player.getGraveyard().getCards(game)) {
|
||||
count++;
|
||||
if (count >= this.minNumberOfTargets) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// 108.4a If anything asks for the controller of a card that doesn't have one (because it's not a permanent or spell), use its owner instead.
|
||||
for (Card card : game.getExile().getAllCards(game)) {
|
||||
if (Objects.equals(card.getOwnerId(), sourceControllerId)) {
|
||||
count++;
|
||||
if (count >= this.minNumberOfTargets) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
public boolean canChoose(UUID sourceControllerId, Ability source, Game game) {
|
||||
return canChooseFromPossibleTargets(sourceControllerId, source, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> possibleTargets(UUID sourceControllerId, Game game) {
|
||||
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
|
||||
Set<UUID> possibleTargets = new HashSet<>();
|
||||
for (StackObject stackObject : game.getStack()) {
|
||||
if (game.getState().getPlayersInRange(sourceControllerId, game).contains(stackObject.getControllerId())
|
||||
|
|
@ -205,7 +168,7 @@ class TargetControlledSource extends TargetSource {
|
|||
}
|
||||
}
|
||||
}
|
||||
return possibleTargets;
|
||||
return keepValidPossibleTargets(possibleTargets, sourceControllerId, source, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -90,10 +90,10 @@ class DistendedMindbenderEffect extends OneShotEffect {
|
|||
TargetCard targetThreeOrLess = new TargetCard(1, Zone.HAND, filterThreeOrLess);
|
||||
TargetCard targetFourOrGreater = new TargetCard(1, Zone.HAND, filterFourOrGreater);
|
||||
Cards toDiscard = new CardsImpl();
|
||||
if (controller.chooseTarget(Outcome.Benefit, opponent.getHand(), targetThreeOrLess, source, game)) {
|
||||
if (controller.choose(Outcome.Benefit, opponent.getHand(), targetThreeOrLess, source, game)) {
|
||||
toDiscard.addAll(targetThreeOrLess.getTargets());
|
||||
}
|
||||
if (controller.chooseTarget(Outcome.Benefit, opponent.getHand(), targetFourOrGreater, source, game)) {
|
||||
if (controller.choose(Outcome.Benefit, opponent.getHand(), targetFourOrGreater, source, game)) {
|
||||
toDiscard.addAll(targetFourOrGreater.getTargets());
|
||||
}
|
||||
opponent.discard(toDiscard, false, source, game);
|
||||
|
|
|
|||
|
|
@ -1,25 +1,26 @@
|
|||
|
||||
package mage.cards.d;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.*;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.cards.Cards;
|
||||
import mage.cards.CardsImpl;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.filter.common.FilterArtifactCard;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.TargetEvent;
|
||||
import mage.game.stack.StackObject;
|
||||
import mage.players.Player;
|
||||
import mage.target.TargetPlayer;
|
||||
import mage.target.common.TargetCardInGraveyard;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author emerald000
|
||||
*/
|
||||
public final class DrafnasRestoration extends CardImpl {
|
||||
|
|
@ -53,27 +54,33 @@ class DrafnasRestorationTarget extends TargetCardInGraveyard {
|
|||
super(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID id, Ability source, Game game) {
|
||||
Player targetPlayer = game.getPlayer(source.getFirstTarget());
|
||||
return targetPlayer != null && targetPlayer.getGraveyard().contains(id) && super.canTarget(id, source, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
|
||||
Set<UUID> possibleTargets = new HashSet<>();
|
||||
MageObject object = game.getObject(source);
|
||||
if (object instanceof StackObject) {
|
||||
Player targetPlayer = game.getPlayer(((StackObject) object).getStackAbility().getFirstTarget());
|
||||
if (targetPlayer != null) {
|
||||
for (Card card : targetPlayer.getGraveyard().getCards(filter, sourceControllerId, source, game)) {
|
||||
if (source == null || source.getSourceId() == null || isNotTarget() || !game.replaceEvent(new TargetEvent(card, source.getSourceId(), sourceControllerId))) {
|
||||
possibleTargets.add(card.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Player controller = game.getPlayer(sourceControllerId);
|
||||
if (controller == null) {
|
||||
return possibleTargets;
|
||||
}
|
||||
return possibleTargets;
|
||||
|
||||
Player targetPlayer = game.getPlayer(source.getFirstTarget());
|
||||
game.getState().getPlayersInRange(sourceControllerId, game, true).stream()
|
||||
.map(game::getPlayer)
|
||||
.filter(Objects::nonNull)
|
||||
.flatMap(player -> player.getGraveyard().getCards(filter, sourceControllerId, source, game).stream())
|
||||
.forEach(card -> {
|
||||
if (targetPlayer == null) {
|
||||
// playable or not selected - use any
|
||||
possibleTargets.add(card.getId());
|
||||
} else {
|
||||
// selected, filter by player
|
||||
if (targetPlayer.getId().equals(card.getControllerOrOwnerId())) {
|
||||
possibleTargets.add(card.getId());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return keepValidPossibleTargets(possibleTargets, sourceControllerId, source, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ class DreamsOfSteelAndOilEffect extends OneShotEffect {
|
|||
filter.add(Predicates.or(CardType.ARTIFACT.getPredicate(), CardType.CREATURE.getPredicate()));
|
||||
TargetCard target = new TargetCard(Zone.HAND, filter);
|
||||
target.withNotTarget(true);
|
||||
controller.chooseTarget(Outcome.Discard, opponent.getHand(), target, source, game);
|
||||
controller.choose(Outcome.Discard, opponent.getHand(), target, source, game);
|
||||
Card card = game.getCard(target.getFirstTarget());
|
||||
if (card != null) {
|
||||
toExile.add(card);
|
||||
|
|
@ -81,7 +81,7 @@ class DreamsOfSteelAndOilEffect extends OneShotEffect {
|
|||
filter.setMessage("artifact or creature card from " + opponent.getName() + "'s graveyard");
|
||||
target = new TargetCard(Zone.GRAVEYARD, filter);
|
||||
target.withNotTarget(true);
|
||||
controller.chooseTarget(Outcome.Exile, opponent.getGraveyard(), target, source, game);
|
||||
controller.choose(Outcome.Exile, opponent.getGraveyard(), target, source, game);
|
||||
card = game.getCard(target.getFirstTarget());
|
||||
if (card != null) {
|
||||
toExile.add(card);
|
||||
|
|
|
|||
|
|
@ -105,11 +105,10 @@ class RevivalExperimentTarget extends TargetCardInYourGraveyard {
|
|||
return cardTypeAssigner.getRoleCount(cards, game) >= cards.size();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
|
||||
Set<UUID> possibleTargets = super.possibleTargets(sourceControllerId, source, game);
|
||||
possibleTargets.removeIf(uuid -> !this.canTarget(sourceControllerId, uuid, null, game));
|
||||
possibleTargets.removeIf(uuid -> !this.canTarget(sourceControllerId, uuid, source, game));
|
||||
return possibleTargets;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,9 +79,7 @@ class EliteSpellbinderEffect extends OneShotEffect {
|
|||
if (controller == null || opponent == null || opponent.getHand().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
TargetCard target = new TargetCardInHand(
|
||||
0, 1, StaticFilters.FILTER_CARD_A_NON_LAND
|
||||
);
|
||||
TargetCard target = new TargetCard(0, 1, Zone.HAND, StaticFilters.FILTER_CARD_A_NON_LAND);
|
||||
controller.choose(outcome, opponent.getHand(), target, source, game);
|
||||
Card card = opponent.getHand().get(target.getFirstTarget(), game);
|
||||
if (card == null) {
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ class EnchantmentAlterationEffect extends OneShotEffect {
|
|||
if (oldPermanent != null
|
||||
&& !oldPermanent.equals(permanentToBeAttachedTo)) {
|
||||
Target auraTarget = aura.getSpellAbility().getTargets().get(0);
|
||||
if (!auraTarget.canTarget(permanentToBeAttachedTo.getId(), game)) {
|
||||
if (!auraTarget.canTarget(permanentToBeAttachedTo.getId(), source, game)) {
|
||||
game.informPlayers(aura.getLogName() + " was not attched to " + permanentToBeAttachedTo.getLogName() + " because it's no legal target for the aura");
|
||||
} else if (oldPermanent.removeAttachment(aura.getId(), source, game)) {
|
||||
game.informPlayers(aura.getLogName() + " was unattached from " + oldPermanent.getLogName() + " and attached to " + permanentToBeAttachedTo.getLogName());
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ enum EverythingComesToDustPredicate implements ObjectSourcePlayerPredicate<Perma
|
|||
if (!p.isCreature(game)){
|
||||
return false;
|
||||
}
|
||||
HashSet<MageObjectReference> set = CardUtil.getSourceCostsTag(game, input.getSource(), ConvokeAbility.convokingCreaturesKey, new HashSet<>(0));
|
||||
HashSet<MageObjectReference> set = CardUtil.getSourceCostsTag(game, input.getSource(), ConvokeAbility.convokingCreaturesKey, new HashSet<>());
|
||||
for (MageObjectReference mor : set){
|
||||
Permanent convoked = game.getPermanentOrLKIBattlefield(mor);
|
||||
if (convoked.shareCreatureTypes(game, p)){
|
||||
|
|
|
|||
|
|
@ -8,9 +8,11 @@ import mage.cards.Cards;
|
|||
import mage.cards.CardsImpl;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.target.TargetCard;
|
||||
import mage.target.common.TargetCardInHand;
|
||||
import mage.target.common.TargetOpponent;
|
||||
import mage.util.CardUtil;
|
||||
|
|
@ -65,9 +67,7 @@ class ExtractBrainEffect extends OneShotEffect {
|
|||
if (controller == null || opponent == null || opponent.getHand().isEmpty() || xValue < 1) {
|
||||
return false;
|
||||
}
|
||||
TargetCardInHand target = new TargetCardInHand(
|
||||
Math.min(opponent.getHand().size(), xValue), StaticFilters.FILTER_CARD
|
||||
);
|
||||
TargetCard target = new TargetCard(Math.min(opponent.getHand().size(), xValue), Integer.MAX_VALUE, Zone.HAND, StaticFilters.FILTER_CARD);
|
||||
opponent.choose(Outcome.Detriment, opponent.getHand(), target, source, game);
|
||||
Cards cards = new CardsImpl(target.getTargets());
|
||||
controller.lookAtCards(source, null, cards, game);
|
||||
|
|
|
|||
|
|
@ -134,7 +134,6 @@ class FireballTargetCreatureOrPlayer extends TargetAnyTarget {
|
|||
continue;
|
||||
}
|
||||
|
||||
possibleTargets.removeAll(getTargets());
|
||||
for (UUID targetId : possibleTargets) {
|
||||
TargetAnyTarget target = this.copy();
|
||||
target.clearChosen();
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ class FrogkinKidnapperEffect extends OneShotEffect {
|
|||
opponent.revealCards(source, opponent.getHand(), game);
|
||||
TargetCard target = new TargetCard(1, Zone.HAND, StaticFilters.FILTER_CARD_A_NON_LAND);
|
||||
Cards toRansom = new CardsImpl();
|
||||
if (controller.chooseTarget(outcome, opponent.getHand(), target, source, game)) {
|
||||
if (controller.choose(outcome, opponent.getHand(), target, source, game)) {
|
||||
toRansom.addAll(target.getTargets());
|
||||
|
||||
String exileName = "Ransomed (owned by " + opponent.getName() + ")";
|
||||
|
|
|
|||
|
|
@ -9,13 +9,12 @@ import mage.abilities.keyword.EquipAbility;
|
|||
import mage.abilities.keyword.TrampleAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.AttachmentType;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.ComparisonType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.*;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.filter.common.FilterCreatureCard;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.filter.predicate.mageobject.ToughnessPredicate;
|
||||
import mage.target.TargetCard;
|
||||
import mage.target.TargetPermanent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
|
|
|||
|
|
@ -69,9 +69,10 @@ class GauntletsOfChaosFirstTarget extends TargetControlledPermanent {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) {
|
||||
if (super.canTarget(controllerId, id, source, game)) {
|
||||
Set<CardType> cardTypes = getOpponentPermanentCardTypes(source.getSourceId(), controllerId, game);
|
||||
public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) {
|
||||
Set<CardType> cardTypes = getOpponentPermanentCardTypes(playerId, game);
|
||||
|
||||
if (super.canTarget(playerId, id, source, game)) {
|
||||
Permanent permanent = game.getPermanent(id);
|
||||
for (CardType type : permanent.getCardType(game)) {
|
||||
if (cardTypes.contains(type)) {
|
||||
|
|
@ -84,23 +85,21 @@ class GauntletsOfChaosFirstTarget extends TargetControlledPermanent {
|
|||
|
||||
@Override
|
||||
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
|
||||
// get all cardtypes from opponents permanents
|
||||
Set<CardType> cardTypes = getOpponentPermanentCardTypes(source.getSourceId(), sourceControllerId, game);
|
||||
Set<CardType> cardTypes = getOpponentPermanentCardTypes(sourceControllerId, game);
|
||||
|
||||
Set<UUID> possibleTargets = new HashSet<>();
|
||||
MageObject targetSource = game.getObject(source);
|
||||
if (targetSource != null) {
|
||||
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) {
|
||||
if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, source, game)) {
|
||||
for (CardType type : permanent.getCardType(game)) {
|
||||
if (cardTypes.contains(type)) {
|
||||
possibleTargets.add(permanent.getId());
|
||||
break;
|
||||
}
|
||||
for (CardType type : permanent.getCardType(game)) {
|
||||
if (cardTypes.contains(type)) {
|
||||
possibleTargets.add(permanent.getId());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return possibleTargets;
|
||||
return keepValidPossibleTargets(possibleTargets, sourceControllerId, source, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -108,7 +107,7 @@ class GauntletsOfChaosFirstTarget extends TargetControlledPermanent {
|
|||
return new GauntletsOfChaosFirstTarget(this);
|
||||
}
|
||||
|
||||
private EnumSet<CardType> getOpponentPermanentCardTypes(UUID sourceId, UUID sourceControllerId, Game game) {
|
||||
private EnumSet<CardType> getOpponentPermanentCardTypes(UUID sourceControllerId, Game game) {
|
||||
Player controller = game.getPlayer(sourceControllerId);
|
||||
EnumSet<CardType> cardTypes = EnumSet.noneOf(CardType.class);
|
||||
if (controller != null) {
|
||||
|
|
@ -125,8 +124,6 @@ class GauntletsOfChaosFirstTarget extends TargetControlledPermanent {
|
|||
|
||||
class GauntletsOfChaosSecondTarget extends TargetPermanent {
|
||||
|
||||
private Permanent firstTarget = null;
|
||||
|
||||
public GauntletsOfChaosSecondTarget() {
|
||||
super();
|
||||
this.filter = this.filter.copy();
|
||||
|
|
@ -136,44 +133,46 @@ class GauntletsOfChaosSecondTarget extends TargetPermanent {
|
|||
|
||||
private GauntletsOfChaosSecondTarget(final GauntletsOfChaosSecondTarget target) {
|
||||
super(target);
|
||||
this.firstTarget = target.firstTarget;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID id, Ability source, Game game) {
|
||||
if (super.canTarget(id, source, game)) {
|
||||
Permanent target1 = game.getPermanent(source.getFirstTarget());
|
||||
Permanent opponentPermanent = game.getPermanent(id);
|
||||
if (target1 != null && opponentPermanent != null) {
|
||||
return target1.shareTypes(opponentPermanent, game);
|
||||
}
|
||||
Permanent ownPermanent = game.getPermanent(source.getFirstTarget());
|
||||
Permanent possiblePermanent = game.getPermanent(id);
|
||||
if (ownPermanent == null || possiblePermanent == null) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
return super.canTarget(id, source, game) && ownPermanent.shareTypes(possiblePermanent, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
|
||||
Set<UUID> possibleTargets = new HashSet<>();
|
||||
if (firstTarget != null) {
|
||||
MageObject targetSource = game.getObject(source);
|
||||
if (targetSource != null) {
|
||||
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) {
|
||||
if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, source, game)) {
|
||||
if (permanent.shareTypes(firstTarget, game)) {
|
||||
possibleTargets.add(permanent.getId());
|
||||
}
|
||||
}
|
||||
|
||||
Permanent ownPermanent = game.getPermanent(source.getFirstTarget());
|
||||
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) {
|
||||
if (ownPermanent == null) {
|
||||
// playable or first target not yet selected
|
||||
// use all
|
||||
possibleTargets.add(permanent.getId());
|
||||
} else {
|
||||
// real
|
||||
// filter by shared type
|
||||
if (permanent.shareTypes(ownPermanent, game)) {
|
||||
possibleTargets.add(permanent.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
return possibleTargets;
|
||||
possibleTargets.removeIf(id -> ownPermanent != null && ownPermanent.getId().equals(id));
|
||||
|
||||
return keepValidPossibleTargets(possibleTargets, sourceControllerId, source, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean chooseTarget(Outcome outcome, UUID playerId, Ability source, Game game) {
|
||||
firstTarget = game.getPermanent(source.getFirstTarget());
|
||||
return super.chooseTarget(Outcome.Damage, playerId, source, game);
|
||||
// AI hint with better outcome
|
||||
return super.chooseTarget(Outcome.GainControl, playerId, source, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ class GhastlordOfFugueEffect extends OneShotEffect {
|
|||
TargetCard target = new TargetCard(Zone.HAND, new FilterCard());
|
||||
target.withNotTarget(true);
|
||||
Card chosenCard = null;
|
||||
if (controller.chooseTarget(Outcome.Benefit, targetPlayer.getHand(), target, source, game)) {
|
||||
if (controller.choose(Outcome.Benefit, targetPlayer.getHand(), target, source, game)) {
|
||||
chosenCard = game.getCard(target.getFirstTarget());
|
||||
}
|
||||
if (chosenCard != null) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
package mage.cards.g;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
import mage.abilities.costs.common.TapSourceCost;
|
||||
|
|
@ -12,15 +11,11 @@ import mage.cards.CardImpl;
|
|||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.constants.TargetController;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.filter.predicate.other.DamagedPlayerThisTurnPredicate;
|
||||
import mage.target.TargetPermanent;
|
||||
import mage.watchers.common.PlayerDamagedBySourceWatcher;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
|
|
@ -28,6 +23,12 @@ import java.util.UUID;
|
|||
*/
|
||||
public final class GiltspireAvenger extends CardImpl {
|
||||
|
||||
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature that dealt damage to you this turn");
|
||||
|
||||
static {
|
||||
filter.add(new DamagedPlayerThisTurnPredicate(TargetController.YOU));
|
||||
}
|
||||
|
||||
public GiltspireAvenger(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{W}{U}");
|
||||
this.subtype.add(SubType.HUMAN);
|
||||
|
|
@ -41,7 +42,7 @@ public final class GiltspireAvenger extends CardImpl {
|
|||
|
||||
// {T}: Destroy target creature that dealt damage to you this turn.
|
||||
Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new TapSourceCost());
|
||||
ability.addTarget(new GiltspireAvengerTarget());
|
||||
ability.addTarget(new TargetPermanent(filter));
|
||||
this.addAbility(ability);
|
||||
|
||||
}
|
||||
|
|
@ -55,64 +56,3 @@ public final class GiltspireAvenger extends CardImpl {
|
|||
return new GiltspireAvenger(this);
|
||||
}
|
||||
}
|
||||
|
||||
class GiltspireAvengerTarget extends TargetPermanent {
|
||||
|
||||
public GiltspireAvengerTarget() {
|
||||
super(1, 1, StaticFilters.FILTER_PERMANENT_CREATURE, false);
|
||||
targetName = "creature that dealt damage to you this turn";
|
||||
}
|
||||
|
||||
private GiltspireAvengerTarget(final GiltspireAvengerTarget target) {
|
||||
super(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID id, Ability source, Game game) {
|
||||
PlayerDamagedBySourceWatcher watcher = game.getState().getWatcher(PlayerDamagedBySourceWatcher.class, source.getControllerId());
|
||||
if (watcher != null && watcher.hasSourceDoneDamage(id, game)) {
|
||||
return super.canTarget(id, source, game);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
|
||||
Set<UUID> availablePossibleTargets = super.possibleTargets(sourceControllerId, source, game);
|
||||
Set<UUID> possibleTargets = new HashSet<>();
|
||||
PlayerDamagedBySourceWatcher watcher = game.getState().getWatcher(PlayerDamagedBySourceWatcher.class, sourceControllerId);
|
||||
for (UUID targetId : availablePossibleTargets) {
|
||||
Permanent permanent = game.getPermanent(targetId);
|
||||
if (permanent != null && watcher != null && watcher.hasSourceDoneDamage(targetId, game)) {
|
||||
possibleTargets.add(targetId);
|
||||
}
|
||||
}
|
||||
return possibleTargets;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canChoose(UUID sourceControllerId, Ability source, Game game) {
|
||||
int remainingTargets = this.minNumberOfTargets - targets.size();
|
||||
if (remainingTargets == 0) {
|
||||
return true;
|
||||
}
|
||||
int count = 0;
|
||||
MageObject targetSource = game.getObject(source);
|
||||
PlayerDamagedBySourceWatcher watcher = game.getState().getWatcher(PlayerDamagedBySourceWatcher.class, sourceControllerId);
|
||||
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) {
|
||||
if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, source, game)
|
||||
&& watcher != null && watcher.hasSourceDoneDamage(permanent.getId(), game)) {
|
||||
count++;
|
||||
if (count >= remainingTargets) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GiltspireAvengerTarget copy() {
|
||||
return new GiltspireAvengerTarget(this);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
package mage.cards.g;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.condition.common.SourceHasCounterCondition;
|
||||
import mage.abilities.decorator.ConditionalContinuousRuleModifyingEffect;
|
||||
|
|
@ -11,11 +9,14 @@ import mage.abilities.effects.OneShotEffect;
|
|||
import mage.abilities.effects.common.DontUntapInControllersUntapStepSourceEffect;
|
||||
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
|
||||
import mage.abilities.effects.common.counter.RemoveCounterSourceEffect;
|
||||
import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.*;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.counters.CounterType;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
|
@ -59,8 +60,6 @@ public final class GlyphOfDelusion extends CardImpl {
|
|||
|
||||
class GlyphOfDelusionSecondTarget extends TargetPermanent {
|
||||
|
||||
private Permanent firstTarget = null;
|
||||
|
||||
public GlyphOfDelusionSecondTarget() {
|
||||
super();
|
||||
withTargetName("target creature that target Wall blocked this turn");
|
||||
|
|
@ -68,33 +67,39 @@ class GlyphOfDelusionSecondTarget extends TargetPermanent {
|
|||
|
||||
private GlyphOfDelusionSecondTarget(final GlyphOfDelusionSecondTarget target) {
|
||||
super(target);
|
||||
this.firstTarget = target.firstTarget;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
|
||||
Set<UUID> possibleTargets = new HashSet<>();
|
||||
if (firstTarget != null) {
|
||||
BlockedAttackerWatcher watcher = game.getState().getWatcher(BlockedAttackerWatcher.class);
|
||||
if (watcher != null) {
|
||||
MageObject targetSource = game.getObject(source);
|
||||
if (targetSource != null) {
|
||||
for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, sourceControllerId, source, game)) {
|
||||
if (!targets.containsKey(creature.getId()) && creature.canBeTargetedBy(targetSource, sourceControllerId, source, game)) {
|
||||
if (watcher.creatureHasBlockedAttacker(new MageObjectReference(creature, game), new MageObjectReference(firstTarget, game))) {
|
||||
possibleTargets.add(creature.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BlockedAttackerWatcher watcher = game.getState().getWatcher(BlockedAttackerWatcher.class);
|
||||
if (watcher == null) {
|
||||
return possibleTargets;
|
||||
}
|
||||
|
||||
Permanent targetWall = game.getPermanent(source.getFirstTarget());
|
||||
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) {
|
||||
if (targetWall == null) {
|
||||
// playable or first target not yet selected
|
||||
// use all
|
||||
possibleTargets.add(permanent.getId());
|
||||
} else {
|
||||
// real
|
||||
// filter by blocked
|
||||
if (watcher.creatureHasBlockedAttacker(new MageObjectReference(permanent, game), new MageObjectReference(targetWall, game))) {
|
||||
possibleTargets.add(permanent.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
return possibleTargets;
|
||||
possibleTargets.removeIf(id -> targetWall != null && targetWall.getId().equals(id));
|
||||
|
||||
return keepValidPossibleTargets(possibleTargets, sourceControllerId, source, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean chooseTarget(Outcome outcome, UUID playerId, Ability source, Game game) {
|
||||
firstTarget = game.getPermanent(source.getFirstTarget());
|
||||
// AI hint with better outcome
|
||||
return super.chooseTarget(Outcome.Tap, playerId, source, game);
|
||||
}
|
||||
|
||||
|
|
@ -133,8 +138,7 @@ class GlyphOfDelusionEffect extends OneShotEffect {
|
|||
effect.setTargetPointer(new FixedTarget(targetPermanent.getId(), game));
|
||||
game.addEffect(effect, source);
|
||||
|
||||
BeginningOfUpkeepTriggeredAbility ability2 = new BeginningOfUpkeepTriggeredAbility(new RemoveCounterSourceEffect(CounterType.GLYPH.createInstance())
|
||||
);
|
||||
BeginningOfUpkeepTriggeredAbility ability2 = new BeginningOfUpkeepTriggeredAbility(new RemoveCounterSourceEffect(CounterType.GLYPH.createInstance()));
|
||||
GainAbilityTargetEffect effect2 = new GainAbilityTargetEffect(ability2, Duration.Custom);
|
||||
effect2.setTargetPointer(new FixedTarget(targetPermanent.getId(), game));
|
||||
game.addEffect(effect2, source);
|
||||
|
|
|
|||
|
|
@ -81,8 +81,8 @@ class GoblinArtisansTarget extends TargetSpell {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) {
|
||||
if (!super.canTarget(controllerId, id, source, game)) {
|
||||
public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) {
|
||||
if (!super.canTarget(playerId, id, source, game)) {
|
||||
return false;
|
||||
}
|
||||
MageObjectReference sourceRef = new MageObjectReference(source.getSourceObject(game), game);
|
||||
|
|
|
|||
|
|
@ -61,8 +61,8 @@ class GracefulTakedownTarget extends TargetPermanent {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) {
|
||||
if (!super.canTarget(controllerId, id, source, game)) {
|
||||
public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) {
|
||||
if (!super.canTarget(playerId, id, source, game)) {
|
||||
return false;
|
||||
}
|
||||
Permanent permanent = game.getPermanent(id);
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ class GrimeGorgerTarget extends TargetCardInGraveyard {
|
|||
@Override
|
||||
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
|
||||
Set<UUID> possibleTargets = super.possibleTargets(sourceControllerId, source, game);
|
||||
possibleTargets.removeIf(uuid -> !this.canTarget(sourceControllerId, uuid, null, game));
|
||||
possibleTargets.removeIf(uuid -> !this.canTarget(sourceControllerId, uuid, source, game));
|
||||
return possibleTargets;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ class GurzigostCost extends CostImpl {
|
|||
|
||||
@Override
|
||||
public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) {
|
||||
return this.getTargets().canChoose(controllerId, source, game);
|
||||
return canChooseOrAlreadyChosen(ability, source, controllerId, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
package mage.cards.i;
|
||||
|
||||
import mage.MageItem;
|
||||
import mage.ObjectColor;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
import mage.abilities.costs.common.RevealTargetFromHandCost;
|
||||
|
|
@ -19,9 +17,9 @@ import mage.game.Game;
|
|||
import mage.target.common.TargetCardInHand;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
|
|
@ -67,51 +65,8 @@ class IlluminatedFolioTarget extends TargetCardInHand {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canChoose(UUID sourceControllerId, Ability source, Game game) {
|
||||
return super.canChoose(sourceControllerId, source, game)
|
||||
&& !possibleTargets(sourceControllerId, source, game).isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
|
||||
Set<UUID> possibleTargets = super.possibleTargets(sourceControllerId, source, game);
|
||||
if (this.getTargets().size() == 1) {
|
||||
Card card = game.getCard(this.getTargets().get(0));
|
||||
possibleTargets.removeIf(
|
||||
uuid -> !game
|
||||
.getCard(uuid)
|
||||
.getColor(game)
|
||||
.shares(card.getColor(game))
|
||||
);
|
||||
return possibleTargets;
|
||||
}
|
||||
if (possibleTargets.size() < 2) {
|
||||
possibleTargets.clear();
|
||||
return possibleTargets;
|
||||
}
|
||||
Set<Card> allTargets = possibleTargets
|
||||
.stream()
|
||||
.map(game::getCard)
|
||||
.collect(Collectors.toSet());
|
||||
possibleTargets.clear();
|
||||
for (ObjectColor color : ObjectColor.getAllColors()) {
|
||||
Set<Card> inColor = allTargets
|
||||
.stream()
|
||||
.filter(card -> card.getColor(game).shares(color))
|
||||
.collect(Collectors.toSet());
|
||||
if (inColor.size() > 1) {
|
||||
inColor.stream().map(MageItem::getId).forEach(possibleTargets::add);
|
||||
}
|
||||
if (possibleTargets.size() == allTargets.size()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return possibleTargets;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID id, Game game) {
|
||||
if (!super.canTarget(id, game)) {
|
||||
public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) {
|
||||
if (!super.canTarget(playerId, id, source, game)) {
|
||||
return false;
|
||||
}
|
||||
List<UUID> targetList = this.getTargets();
|
||||
|
|
@ -123,9 +78,17 @@ class IlluminatedFolioTarget extends TargetCardInHand {
|
|||
&& targetList
|
||||
.stream()
|
||||
.map(game::getCard)
|
||||
.filter(Objects::nonNull)
|
||||
.anyMatch(c -> c.getColor(game).shares(card.getColor(game)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
|
||||
Set<UUID> possibleTargets = super.possibleTargets(sourceControllerId, source, game);
|
||||
possibleTargets.removeIf(uuid -> !this.canTarget(sourceControllerId, uuid, source, game));
|
||||
return possibleTargets;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IlluminatedFolioTarget copy() {
|
||||
return new IlluminatedFolioTarget(this);
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ class ImpelledGiantCost extends CostImpl {
|
|||
|
||||
@Override
|
||||
public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) {
|
||||
return target.canChoose(controllerId, source, game);
|
||||
return target.canChooseOrAlreadyChosen(controllerId, source, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -79,9 +79,7 @@ class InvasionOfGobakhanEffect extends OneShotEffect {
|
|||
if (controller == null || opponent == null || opponent.getHand().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
TargetCard target = new TargetCardInHand(
|
||||
0, 1, StaticFilters.FILTER_CARD_A_NON_LAND
|
||||
);
|
||||
TargetCard target = new TargetCard(0, 1, Zone.HAND, StaticFilters.FILTER_CARD_A_NON_LAND);
|
||||
controller.choose(outcome, opponent.getHand(), target, source, game);
|
||||
Card card = opponent.getHand().get(target.getFirstTarget(), game);
|
||||
if (card == null) {
|
||||
|
|
|
|||
|
|
@ -1,32 +1,27 @@
|
|||
|
||||
package mage.cards.i;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.keyword.TrampleAbility;
|
||||
import mage.cards.*;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SuperType;
|
||||
import mage.constants.Zone;
|
||||
import mage.constants.*;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.target.Target;
|
||||
import mage.target.common.TargetCardInHand;
|
||||
import mage.target.TargetCard;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public final class IwamoriOfTheOpenFist extends CardImpl {
|
||||
|
||||
public IwamoriOfTheOpenFist(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}{G}");
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{G}");
|
||||
this.supertype.add(SuperType.LEGENDARY);
|
||||
this.subtype.add(SubType.HUMAN);
|
||||
this.subtype.add(SubType.MONK);
|
||||
|
|
@ -80,15 +75,11 @@ class IwamoriOfTheOpenFistEffect extends OneShotEffect {
|
|||
Cards cards = new CardsImpl();
|
||||
for (UUID playerId : game.getOpponents(controller.getId())) {
|
||||
Player opponent = game.getPlayer(playerId);
|
||||
Target target = new TargetCardInHand(filter);
|
||||
if (opponent != null && target.canChoose(opponent.getId(), source, game)) {
|
||||
if (opponent.chooseUse(Outcome.PutCreatureInPlay, "Put a legendary creature card from your hand onto the battlefield?", source, game)) {
|
||||
if (target.chooseTarget(Outcome.PutCreatureInPlay, opponent.getId(), source, game)) {
|
||||
Card card = game.getCard(target.getFirstTarget());
|
||||
if (card != null) {
|
||||
cards.add(card);
|
||||
}
|
||||
}
|
||||
Target target = new TargetCard(0, 1, Zone.HAND, filter).withChooseHint("put from hand to battlefield");
|
||||
if (target.choose(Outcome.PutCreatureInPlay, opponent.getId(), source, game)) {
|
||||
Card card = game.getCard(target.getFirstTarget());
|
||||
if (card != null) {
|
||||
cards.add(card);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ class JotunGruntCost extends CostImpl {
|
|||
|
||||
@Override
|
||||
public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) {
|
||||
return this.getTargets().canChoose(controllerId, source, game);
|
||||
return canChooseOrAlreadyChosen(ability, source, controllerId, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import mage.filter.predicate.mageobject.NamePredicate;
|
|||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.target.TargetCard;
|
||||
import mage.target.common.TargetCardInLibrary;
|
||||
import mage.target.common.TargetCardInYourGraveyard;
|
||||
|
||||
import java.util.Objects;
|
||||
|
|
@ -62,28 +61,31 @@ class JourneyForTheElixirEffect extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
if (player == null) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller == null) {
|
||||
return false;
|
||||
}
|
||||
TargetCardInLibrary targetCardInLibrary = new JourneyForTheElixirLibraryTarget();
|
||||
player.searchLibrary(targetCardInLibrary, source, game);
|
||||
Cards cards = new CardsImpl(targetCardInLibrary.getTargets());
|
||||
TargetCard target = new JourneyForTheElixirGraveyardTarget(cards);
|
||||
player.choose(outcome, target, source, game);
|
||||
cards.addAll(target.getTargets());
|
||||
player.revealCards(source, cards, game);
|
||||
player.moveCards(cards, Zone.HAND, source, game);
|
||||
player.shuffleLibrary(source, game);
|
||||
return true;
|
||||
|
||||
// search your library and graveyard for 2 cards
|
||||
Cards allCards = new CardsImpl();
|
||||
allCards.addAll(controller.getLibrary().getCardList());
|
||||
allCards.addAll(controller.getGraveyard());
|
||||
TargetCard target = new JourneyForTheElixirTarget();
|
||||
if (controller.choose(Outcome.Benefit, allCards, target, source, game)) {
|
||||
Cards cards = new CardsImpl(target.getTargets());
|
||||
controller.revealCards(source, cards, game);
|
||||
controller.moveCards(cards, Zone.HAND, source, game);
|
||||
controller.shuffleLibrary(source, game);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class JourneyForTheElixirLibraryTarget extends TargetCardInLibrary {
|
||||
class JourneyForTheElixirTarget extends TargetCard {
|
||||
|
||||
private static final String name = "Jiang Yanggu";
|
||||
private static final FilterCard filter
|
||||
= new FilterCard("a basic land card and a card named Jiang Yanggu");
|
||||
private static final FilterCard filter = new FilterCard("a basic land card and a card named Jiang Yanggu");
|
||||
|
||||
static {
|
||||
filter.add(Predicates.or(
|
||||
|
|
@ -95,17 +97,17 @@ class JourneyForTheElixirLibraryTarget extends TargetCardInLibrary {
|
|||
));
|
||||
}
|
||||
|
||||
JourneyForTheElixirLibraryTarget() {
|
||||
super(0, 2, filter);
|
||||
JourneyForTheElixirTarget() {
|
||||
super(2, 2, Zone.ALL, filter);
|
||||
}
|
||||
|
||||
private JourneyForTheElixirLibraryTarget(final JourneyForTheElixirLibraryTarget target) {
|
||||
private JourneyForTheElixirTarget(final JourneyForTheElixirTarget target) {
|
||||
super(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JourneyForTheElixirLibraryTarget copy() {
|
||||
return new JourneyForTheElixirLibraryTarget(this);
|
||||
public JourneyForTheElixirTarget copy() {
|
||||
return new JourneyForTheElixirTarget(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -117,95 +119,35 @@ class JourneyForTheElixirLibraryTarget extends TargetCardInLibrary {
|
|||
if (card == null) {
|
||||
return false;
|
||||
}
|
||||
if (this.getTargets().isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Cards cards = new CardsImpl(this.getTargets());
|
||||
if (card.isBasic(game)
|
||||
&& card.isLand(game)
|
||||
&& cards
|
||||
boolean hasLand = cards
|
||||
.getCards(game)
|
||||
.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.filter(c -> c.isBasic(game))
|
||||
.anyMatch(c -> c.isLand(game))) {
|
||||
return false;
|
||||
}
|
||||
if (name.equals(card.getName())
|
||||
&& cards
|
||||
.anyMatch(c -> c.isLand(game));
|
||||
boolean hasJiang = cards
|
||||
.getCards(game)
|
||||
.stream()
|
||||
.map(MageObject::getName)
|
||||
.anyMatch(name::equals)) {
|
||||
return false;
|
||||
.anyMatch(name::equals);
|
||||
|
||||
if (!hasLand && card.isBasic(game) && card.isLand(game)) {
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class JourneyForTheElixirGraveyardTarget extends TargetCardInYourGraveyard {
|
||||
if (!hasJiang && name.equals(card.getName())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static final String name = "Jiang Yanggu";
|
||||
private static final FilterCard filter
|
||||
= new FilterCard("a basic land card and a card named Jiang Yanggu");
|
||||
|
||||
static {
|
||||
filter.add(Predicates.or(
|
||||
Predicates.and(
|
||||
SuperType.BASIC.getPredicate(),
|
||||
CardType.LAND.getPredicate()
|
||||
),
|
||||
new NamePredicate(name)
|
||||
));
|
||||
}
|
||||
|
||||
private final Cards cards = new CardsImpl();
|
||||
|
||||
JourneyForTheElixirGraveyardTarget(Cards cards) {
|
||||
super(0, Integer.MAX_VALUE, filter, true);
|
||||
this.cards.addAll(cards);
|
||||
}
|
||||
|
||||
private JourneyForTheElixirGraveyardTarget(final JourneyForTheElixirGraveyardTarget target) {
|
||||
super(target);
|
||||
this.cards.addAll(target.cards);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JourneyForTheElixirGraveyardTarget copy() {
|
||||
return new JourneyForTheElixirGraveyardTarget(this);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
|
||||
Set<UUID> possibleTargets = super.possibleTargets(sourceControllerId, source, game);
|
||||
Cards alreadyTargeted = new CardsImpl(this.getTargets());
|
||||
alreadyTargeted.addAll(cards);
|
||||
boolean hasBasic = alreadyTargeted
|
||||
.getCards(game)
|
||||
.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.filter(c -> c.isLand(game))
|
||||
.anyMatch(c -> c.isBasic(game));
|
||||
possibleTargets.removeIf(uuid -> {
|
||||
Card card = game.getCard(uuid);
|
||||
return card != null
|
||||
&& hasBasic
|
||||
&& card.isLand(game)
|
||||
&& card.isBasic(game);
|
||||
});
|
||||
boolean hasYanggu = alreadyTargeted
|
||||
.getCards(game)
|
||||
.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.map(MageObject::getName)
|
||||
.anyMatch(name::equals);
|
||||
possibleTargets.removeIf(uuid -> {
|
||||
Card card = game.getCard(uuid);
|
||||
return card != null
|
||||
&& hasYanggu
|
||||
&& name.equals(card.getName());
|
||||
});
|
||||
possibleTargets.removeIf(uuid -> !this.canTarget(sourceControllerId, uuid, source, game));
|
||||
return possibleTargets;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,8 +88,8 @@ class KairiTheSwirlingSkyTarget extends TargetPermanent {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) {
|
||||
return super.canTarget(controllerId, id, source, game)
|
||||
public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) {
|
||||
return super.canTarget(playerId, id, source, game)
|
||||
&& CardUtil.checkCanTargetTotalValueLimit(
|
||||
this.getTargets(), id, MageObject::getManaValue, 6, game);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package mage.cards.k;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
import mage.abilities.costs.common.TapSourceCost;
|
||||
|
|
@ -15,10 +14,8 @@ import mage.filter.FilterOpponent;
|
|||
import mage.filter.StaticFilters;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.token.BeastToken4;
|
||||
import mage.players.Player;
|
||||
import mage.target.TargetPlayer;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
|
|
@ -35,7 +32,7 @@ public final class KeeperOfTheBeasts extends CardImpl {
|
|||
this.power = new MageInt(1);
|
||||
this.toughness = new MageInt(2);
|
||||
|
||||
// {G}, {tap}: Choose target opponent who controlled more creatures than you did as you activated this ability. Put a 2/2 green Beast creature token onto the battlefield.
|
||||
// {G}, {T}: Choose target opponent who controlled more creatures than you did as you activated this ability. Put a 2/2 green Beast creature token onto the battlefield.
|
||||
Ability ability = new SimpleActivatedAbility(new CreateTokenEffect(new BeastToken4()).setText("Choose target opponent who controlled more creatures than you did as you activated this ability. Create a 2/2 green Beast creature token."),
|
||||
new ManaCostsImpl<>("{G}"));
|
||||
ability.addCost(new TapSourceCost());
|
||||
|
|
@ -65,42 +62,12 @@ class KeeperOfTheBeastsTarget extends TargetPlayer {
|
|||
|
||||
@Override
|
||||
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
|
||||
Set<UUID> availablePossibleTargets = super.possibleTargets(sourceControllerId, source, game);
|
||||
Set<UUID> possibleTargets = new HashSet<>();
|
||||
int creaturesController = game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_CREATURE, sourceControllerId, game);
|
||||
|
||||
for (UUID targetId : availablePossibleTargets) {
|
||||
if (game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_CREATURE, targetId, game) > creaturesController) {
|
||||
possibleTargets.add(targetId);
|
||||
}
|
||||
}
|
||||
Set<UUID> possibleTargets = super.possibleTargets(sourceControllerId, source, game);
|
||||
int myCount = game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_CREATURE, sourceControllerId, game);
|
||||
possibleTargets.removeIf(playerId -> game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_CREATURE, playerId, game) < myCount);
|
||||
return possibleTargets;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canChoose(UUID sourceControllerId, Ability source, Game game) {
|
||||
int count = 0;
|
||||
MageObject targetSource = game.getObject(source);
|
||||
Player controller = game.getPlayer(sourceControllerId);
|
||||
if (controller != null && targetSource != null) {
|
||||
for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) {
|
||||
Player player = game.getPlayer(playerId);
|
||||
if (player != null
|
||||
&& game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_CREATURE, sourceControllerId, game)
|
||||
< game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_CREATURE, playerId, game)
|
||||
&& !player.hasLeft()
|
||||
&& filter.match(player, sourceControllerId, source, game)
|
||||
&& player.canBeTargetedBy(targetSource, sourceControllerId, source, game)) {
|
||||
count++;
|
||||
if (count >= this.minNumberOfTargets) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeeperOfTheBeastsTarget copy() {
|
||||
return new KeeperOfTheBeastsTarget(this);
|
||||
|
|
|
|||
|
|
@ -1,10 +1,7 @@
|
|||
package mage.cards.k;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.MageObject;
|
||||
import mage.ObjectColor;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
import mage.abilities.costs.common.TapSourceCost;
|
||||
|
|
@ -15,21 +12,23 @@ import mage.cards.CardSetInfo;
|
|||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterPlayer;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.filter.predicate.ObjectSourcePlayer;
|
||||
import mage.filter.predicate.ObjectSourcePlayerPredicate;
|
||||
import mage.filter.predicate.Predicates;
|
||||
import mage.filter.predicate.mageobject.ColorPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.stack.StackObject;
|
||||
import mage.players.Player;
|
||||
import mage.target.TargetPermanent;
|
||||
import mage.target.TargetPlayer;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author spjspj
|
||||
*/
|
||||
public final class KeeperOfTheDead extends CardImpl {
|
||||
|
|
@ -95,48 +94,37 @@ class KeeperOfDeadPredicate implements ObjectSourcePlayerPredicate<Player> {
|
|||
|
||||
class KeeperOfTheDeadCreatureTarget extends TargetPermanent {
|
||||
|
||||
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nonblack creature that player controls");
|
||||
|
||||
static {
|
||||
filter.add(Predicates.not(new ColorPredicate(ObjectColor.BLACK)));
|
||||
}
|
||||
|
||||
public KeeperOfTheDeadCreatureTarget() {
|
||||
super(1, 1, new FilterCreaturePermanent("nonblack creature that player controls"), false);
|
||||
super(1, 1, filter);
|
||||
}
|
||||
|
||||
private KeeperOfTheDeadCreatureTarget(final KeeperOfTheDeadCreatureTarget target) {
|
||||
super(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID id, Ability source, Game game) {
|
||||
UUID firstTarget = source.getFirstTarget();
|
||||
Permanent permanent = game.getPermanent(id);
|
||||
if (firstTarget != null && permanent != null && permanent.isControlledBy(firstTarget)) {
|
||||
return super.canTarget(id, source, game);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
|
||||
Set<UUID> availablePossibleTargets = super.possibleTargets(sourceControllerId, source, game);
|
||||
Set<UUID> possibleTargets = new HashSet<>();
|
||||
MageObject object = game.getObject(source);
|
||||
Set<UUID> possibleTargets = super.possibleTargets(sourceControllerId, source, game);
|
||||
|
||||
for (StackObject item : game.getState().getStack()) {
|
||||
if (item.getId().equals(source.getSourceId())) {
|
||||
object = item;
|
||||
}
|
||||
if (item.getSourceId().equals(source.getSourceId())) {
|
||||
object = item;
|
||||
}
|
||||
Player needPlayer = game.getPlayerOrPlaneswalkerController(source.getFirstTarget());
|
||||
if (needPlayer == null) {
|
||||
// playable or not selected - use any
|
||||
} else {
|
||||
// filter by controller
|
||||
possibleTargets.removeIf(id -> {
|
||||
Permanent permanent = game.getPermanent(id);
|
||||
return permanent == null
|
||||
|| permanent.getId().equals(source.getFirstTarget())
|
||||
|| !permanent.isControlledBy(needPlayer.getId());
|
||||
});
|
||||
}
|
||||
|
||||
if (object instanceof StackObject) {
|
||||
UUID playerId = ((StackObject) object).getStackAbility().getFirstTarget();
|
||||
for (UUID targetId : availablePossibleTargets) {
|
||||
Permanent permanent = game.getPermanent(targetId);
|
||||
if (permanent != null && StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK.match(permanent, game) && permanent.isControlledBy(playerId)) {
|
||||
possibleTargets.add(targetId);
|
||||
}
|
||||
}
|
||||
}
|
||||
return possibleTargets;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
|
||||
package mage.cards.k;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
import mage.abilities.costs.common.TapSourceCost;
|
||||
|
|
@ -12,13 +10,11 @@ import mage.cards.CardImpl;
|
|||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterOpponent;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.target.TargetPlayer;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
|
|
@ -67,43 +63,19 @@ class KeeperOfTheLightTarget extends TargetPlayer {
|
|||
|
||||
@Override
|
||||
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
|
||||
Set<UUID> availablePossibleTargets = super.possibleTargets(sourceControllerId, source, game);
|
||||
Set<UUID> possibleTargets = new HashSet<>();
|
||||
int lifeController = game.getPlayer(sourceControllerId).getLife();
|
||||
Set<UUID> possibleTargets = super.possibleTargets(sourceControllerId, source, game);
|
||||
|
||||
for (UUID targetId : availablePossibleTargets) {
|
||||
Player opponent = game.getPlayer(targetId);
|
||||
if (opponent != null) {
|
||||
int lifeOpponent = opponent.getLife();
|
||||
if (lifeOpponent > lifeController) {
|
||||
possibleTargets.add(targetId);
|
||||
}
|
||||
}
|
||||
}
|
||||
return possibleTargets;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canChoose(UUID sourceControllerId, Ability source, Game game) {
|
||||
int count = 0;
|
||||
MageObject targetSource = game.getObject(source);
|
||||
Player controller = game.getPlayer(sourceControllerId);
|
||||
if (controller != null && targetSource != null) {
|
||||
for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) {
|
||||
Player player = game.getPlayer(playerId);
|
||||
if (player != null
|
||||
&& controller.getLife() < player.getLife()
|
||||
&& !player.hasLeft()
|
||||
&& filter.match(player, sourceControllerId, source, game)
|
||||
&& player.canBeTargetedBy(targetSource, sourceControllerId, source, game)) {
|
||||
count++;
|
||||
if (count >= this.minNumberOfTargets) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (controller == null) {
|
||||
return possibleTargets;
|
||||
}
|
||||
return false;
|
||||
|
||||
possibleTargets.removeIf(playerId -> {
|
||||
Player player = game.getPlayer(playerId);
|
||||
return player == null || player.getLife() >= controller.getLife();
|
||||
});
|
||||
|
||||
return possibleTargets;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ class KeldonBattlewagonCost extends CostImpl {
|
|||
|
||||
@Override
|
||||
public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) {
|
||||
return target.canChoose(controllerId, source, game);
|
||||
return target.canChooseOrAlreadyChosen(controllerId, source, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -7,15 +7,14 @@ import mage.abilities.effects.common.continuous.BoostAllEffect;
|
|||
import mage.abilities.keyword.EquipAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.SuperType;
|
||||
import mage.constants.*;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.filter.common.FilterCreatureCard;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.target.TargetCard;
|
||||
import mage.target.TargetPermanent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import mage.game.Game;
|
|||
import mage.game.events.GameEvent;
|
||||
import mage.game.stack.Spell;
|
||||
import mage.players.Player;
|
||||
import mage.target.TargetCard;
|
||||
import mage.target.common.TargetCardInGraveyard;
|
||||
import mage.target.common.TargetCardInHand;
|
||||
import mage.target.common.TargetCardInLibrary;
|
||||
|
|
@ -107,9 +108,9 @@ class KotoseTheSilentSpiderEffect extends OneShotEffect {
|
|||
cards.addAll(targetCardInGraveyard.getTargets());
|
||||
|
||||
filter.setMessage("cards named " + card.getName() + " from " + opponent.getName() + "'s hand");
|
||||
TargetCardInHand targetCardInHand = new TargetCardInHand(0, Integer.MAX_VALUE, filter);
|
||||
controller.choose(outcome, opponent.getHand(), targetCardInHand, source, game);
|
||||
cards.addAll(targetCardInHand.getTargets());
|
||||
TargetCard targetCard = new TargetCard(0, Integer.MAX_VALUE, Zone.HAND, filter);
|
||||
controller.choose(outcome, opponent.getHand(), targetCard, source, game);
|
||||
cards.addAll(targetCard.getTargets());
|
||||
|
||||
filter.setMessage("cards named " + card.getName() + " from " + opponent.getName() + "'s library");
|
||||
TargetCardInLibrary target = new TargetCardInLibrary(0, Integer.MAX_VALUE, filter);
|
||||
|
|
|
|||
|
|
@ -130,8 +130,8 @@ class LagrellaTheMagpieTarget extends TargetPermanent {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) {
|
||||
if (!super.canTarget(controllerId, id, source, game)) {
|
||||
public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) {
|
||||
if (!super.canTarget(playerId, id, source, game)) {
|
||||
return false;
|
||||
}
|
||||
Permanent creature = game.getPermanent(id);
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ class LethalSchemeEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
HashSet<MageObjectReference> convokingCreatures = CardUtil.getSourceCostsTag(game, source,
|
||||
ConvokeAbility.convokingCreaturesKey, new HashSet<>(0));
|
||||
ConvokeAbility.convokingCreaturesKey, new HashSet<>());
|
||||
Set<AbstractMap.SimpleEntry<UUID, Permanent>> playerPermanentsPairs =
|
||||
convokingCreatures
|
||||
.stream()
|
||||
|
|
|
|||
|
|
@ -103,8 +103,8 @@ class LivelyDirgeTarget extends TargetCardInYourGraveyard {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) {
|
||||
return super.canTarget(controllerId, id, source, game)
|
||||
public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) {
|
||||
return super.canTarget(playerId, id, source, game)
|
||||
&& CardUtil.checkCanTargetTotalValueLimit(
|
||||
this.getTargets(), id, MageObject::getManaValue, 4, game);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ class LobotomyEffect extends SearchTargetGraveyardHandLibraryForCardNameAndExile
|
|||
TargetCard target = new TargetCard(Zone.HAND, filter);
|
||||
target.withNotTarget(true);
|
||||
Card chosenCard = null;
|
||||
if (controller.chooseTarget(Outcome.Benefit, targetPlayer.getHand(), target, source, game)) {
|
||||
if (controller.choose(Outcome.Benefit, targetPlayer.getHand(), target, source, game)) {
|
||||
chosenCard = game.getCard(target.getFirstTarget());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ import java.util.Set;
|
|||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author weirddan455
|
||||
*/
|
||||
public final class LongRest extends CardImpl {
|
||||
|
|
@ -67,19 +66,22 @@ class LongRestTarget extends TargetCardInYourGraveyard {
|
|||
@Override
|
||||
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
|
||||
Set<UUID> possibleTargets = new HashSet<>();
|
||||
Set<Integer> manaValues = new HashSet<>();
|
||||
|
||||
Set<Integer> usedManaValues = new HashSet<>();
|
||||
for (UUID targetId : this.getTargets()) {
|
||||
Card card = game.getCard(targetId);
|
||||
if (card != null) {
|
||||
manaValues.add(card.getManaValue());
|
||||
usedManaValues.add(card.getManaValue());
|
||||
}
|
||||
}
|
||||
|
||||
for (UUID possibleTargetId : super.possibleTargets(sourceControllerId, source, game)) {
|
||||
Card card = game.getCard(possibleTargetId);
|
||||
if (card != null && !manaValues.contains(card.getManaValue())) {
|
||||
if (card != null && !usedManaValues.contains(card.getManaValue())) {
|
||||
possibleTargets.add(possibleTargetId);
|
||||
}
|
||||
}
|
||||
|
||||
return possibleTargets;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,8 +56,8 @@ class MarchFromTheTombTarget extends TargetCardInYourGraveyard {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) {
|
||||
return super.canTarget(controllerId, id, source, game)
|
||||
public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) {
|
||||
return super.canTarget(playerId, id, source, game)
|
||||
&& CardUtil.checkCanTargetTotalValueLimit(
|
||||
this.getTargets(), id, MageObject::getManaValue, 8, game);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,8 +86,8 @@ class ModifyMemoryTarget extends TargetPermanent {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) {
|
||||
if (!super.canTarget(controllerId, id, source, game)) {
|
||||
public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) {
|
||||
if (!super.canTarget(playerId, id, source, game)) {
|
||||
return false;
|
||||
}
|
||||
Permanent creature = game.getPermanent(id);
|
||||
|
|
|
|||
|
|
@ -112,8 +112,8 @@ class MoorlandRescuerTarget extends TargetCardInYourGraveyard {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) {
|
||||
return super.canTarget(controllerId, id, source, game)
|
||||
public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) {
|
||||
return super.canTarget(playerId, id, source, game)
|
||||
&& CardUtil.checkCanTargetTotalValueLimit(
|
||||
this.getTargets(), id, m -> m.getPower().getValue(), xValue, game);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package mage.cards.m;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.CardImpl;
|
||||
|
|
@ -9,18 +8,16 @@ import mage.constants.CardType;
|
|||
import mage.constants.Outcome;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.filter.predicate.Predicates;
|
||||
import mage.filter.predicate.permanent.ControllerIdPredicate;
|
||||
import mage.filter.predicate.permanent.PermanentIdPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.target.TargetPermanent;
|
||||
import mage.target.common.TargetCreaturePermanent;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* TODO: combine with BreakingOfTheFellowship
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public final class Mutiny extends CardImpl {
|
||||
|
|
@ -30,7 +27,8 @@ public final class Mutiny extends CardImpl {
|
|||
|
||||
// Target creature an opponent controls deals damage equal to its power to another target creature that player controls.
|
||||
this.getSpellAbility().addEffect(new MutinyEffect());
|
||||
this.getSpellAbility().addTarget(new MutinyFirstTarget(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE));
|
||||
this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE));
|
||||
this.getSpellAbility().addTarget(new MutinySecondTarget());
|
||||
this.getSpellAbility().addTarget(new TargetPermanent(new FilterCreaturePermanent("another target creature that player controls")));
|
||||
}
|
||||
|
||||
|
|
@ -72,74 +70,45 @@ class MutinyEffect extends OneShotEffect {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class MutinyFirstTarget extends TargetPermanent {
|
||||
class MutinySecondTarget extends TargetPermanent {
|
||||
|
||||
public MutinyFirstTarget(FilterCreaturePermanent filter) {
|
||||
super(1, 1, filter, false);
|
||||
public MutinySecondTarget() {
|
||||
super(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE);
|
||||
}
|
||||
|
||||
private MutinyFirstTarget(final MutinyFirstTarget target) {
|
||||
private MutinySecondTarget(final MutinySecondTarget target) {
|
||||
super(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTarget(UUID id, Ability source, Game game, boolean skipEvent) {
|
||||
super.addTarget(id, source, game, skipEvent);
|
||||
// Update the second target
|
||||
UUID firstController = game.getControllerId(id);
|
||||
if (firstController != null && source.getTargets().size() > 1) {
|
||||
Player controllingPlayer = game.getPlayer(firstController);
|
||||
TargetCreaturePermanent targetCreaturePermanent = (TargetCreaturePermanent) source.getTargets().get(1);
|
||||
// Set a new filter to the second target with the needed restrictions
|
||||
FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature that player " + controllingPlayer.getName() + " controls");
|
||||
filter.add(new ControllerIdPredicate(firstController));
|
||||
filter.add(Predicates.not(new PermanentIdPredicate(id)));
|
||||
targetCreaturePermanent.replaceFilter(filter);
|
||||
}
|
||||
}
|
||||
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
|
||||
Set<UUID> possibleTargets = super.possibleTargets(sourceControllerId, source, game);
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) {
|
||||
if (super.canTarget(controllerId, id, source, game)) {
|
||||
// can only target, if the controller has at least two targetable creatures
|
||||
UUID controllingPlayerId = game.getControllerId(id);
|
||||
int possibleTargets = 0;
|
||||
MageObject sourceObject = game.getObject(source.getId());
|
||||
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, controllingPlayerId, game)) {
|
||||
if (permanent.canBeTargetedBy(sourceObject, controllerId, source, game)) {
|
||||
possibleTargets++;
|
||||
}
|
||||
Permanent firstTarget = game.getPermanent(source.getFirstTarget());
|
||||
if (firstTarget == null) {
|
||||
// playable or first target not yet selected
|
||||
// use all
|
||||
if (possibleTargets.size() == 1) {
|
||||
// workaround to make 1 target invalid
|
||||
possibleTargets.clear();
|
||||
}
|
||||
return possibleTargets > 1;
|
||||
} else {
|
||||
// real
|
||||
// filter by same player
|
||||
possibleTargets.removeIf(id -> {
|
||||
Permanent permanent = game.getPermanent(id);
|
||||
return permanent == null || !permanent.isControlledBy(firstTarget.getControllerId());
|
||||
});
|
||||
}
|
||||
return false;
|
||||
possibleTargets.removeIf(id -> firstTarget != null && firstTarget.getId().equals(id));
|
||||
|
||||
return possibleTargets;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canChoose(UUID sourceControllerId, Ability source, Game game) {
|
||||
if (super.canChoose(sourceControllerId, source, game)) {
|
||||
UUID controllingPlayerId = game.getControllerId(source.getSourceId());
|
||||
for (UUID playerId : game.getOpponents(controllingPlayerId)) {
|
||||
int possibleTargets = 0;
|
||||
MageObject sourceObject = game.getObject(source);
|
||||
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, playerId, game)) {
|
||||
if (permanent.canBeTargetedBy(sourceObject, controllingPlayerId, source, game)) {
|
||||
possibleTargets++;
|
||||
}
|
||||
}
|
||||
if (possibleTargets > 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MutinyFirstTarget copy() {
|
||||
return new MutinyFirstTarget(this);
|
||||
public MutinySecondTarget copy() {
|
||||
return new MutinySecondTarget(this);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,10 +22,7 @@ import mage.target.common.TargetCardInYourGraveyard;
|
|||
import mage.util.CardUtil;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
|
|
@ -113,7 +110,10 @@ class NethergoyfTarget extends TargetCardInYourGraveyard {
|
|||
return false;
|
||||
}
|
||||
// Check that exiling all the possible cards would have >= 4 different card types
|
||||
return metCondition(this.possibleTargets(sourceControllerId, source, game), game);
|
||||
Set<UUID> idsToCheck = new HashSet<>();
|
||||
idsToCheck.addAll(this.getTargets());
|
||||
idsToCheck.addAll(this.possibleTargets(sourceControllerId, source, game));
|
||||
return metCondition(idsToCheck, game);
|
||||
}
|
||||
|
||||
private static Set<CardType> typesAmongSelection(Collection<UUID> cardsIds, Game game) {
|
||||
|
|
|
|||
|
|
@ -83,8 +83,8 @@ class NethroiApexOfDeathTarget extends TargetCardInYourGraveyard {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) {
|
||||
return super.canTarget(controllerId, id, source, game)
|
||||
public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) {
|
||||
return super.canTarget(playerId, id, source, game)
|
||||
&& CardUtil.checkCanTargetTotalValueLimit(
|
||||
this.getTargets(), id, m -> m.getPower().getValue(), 10, game);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ class NicolBolasDragonGodPlusOneEffect extends OneShotEffect {
|
|||
TargetPermanent targetPermanent = new TargetControlledPermanent();
|
||||
targetPermanent.withNotTarget(true);
|
||||
targetPermanent.setTargetController(opponentId);
|
||||
if (!targetPermanent.possibleTargets(opponentId, game).isEmpty()) {
|
||||
if (!targetPermanent.possibleTargets(opponentId, source, game).isEmpty()) {
|
||||
possibleTargetTypes.add(targetPermanent);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ class NivmagusElementalCost extends CostImpl {
|
|||
|
||||
@Override
|
||||
public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) {
|
||||
return this.getTargets().canChoose(controllerId, source, game);
|
||||
return canChooseOrAlreadyChosen(ability, source, controllerId, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package mage.cards.n;
|
||||
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.common.FightTargetsEffect;
|
||||
import mage.cards.Card;
|
||||
|
|
@ -15,7 +16,9 @@ import mage.game.permanent.Permanent;
|
|||
import mage.game.stack.Spell;
|
||||
import mage.target.TargetPermanent;
|
||||
import mage.target.common.TargetControlledCreaturePermanent;
|
||||
import mage.watchers.common.BlockedAttackerWatcher;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
|
|
@ -54,50 +57,27 @@ class TargetCreatureWithLessPowerPermanent extends TargetPermanent {
|
|||
super(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canChoose(UUID sourceControllerId, Ability source, Game game) {
|
||||
int maxPower = Integer.MIN_VALUE; // get the most powerful controlled creature that can be targeted
|
||||
Card sourceCard = game.getCard(source.getSourceId());
|
||||
if (sourceCard == null) {
|
||||
return false;
|
||||
}
|
||||
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURES, sourceControllerId, game)) {
|
||||
if (permanent.getPower().getValue() > maxPower && permanent.canBeTargetedBy(sourceCard, sourceControllerId, source, game)) {
|
||||
maxPower = permanent.getPower().getValue();
|
||||
}
|
||||
}
|
||||
// now check, if another creature has less power and can be targeted
|
||||
FilterCreaturePermanent checkFilter = new FilterCreaturePermanent();
|
||||
checkFilter.add(new PowerPredicate(ComparisonType.FEWER_THAN, maxPower));
|
||||
for (Permanent permanent : game.getBattlefield().getActivePermanents(checkFilter, sourceControllerId, source, game)) {
|
||||
if (permanent.canBeTargetedBy(sourceCard, sourceControllerId, source, game)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
|
||||
Spell spell = game.getStack().getSpell(source.getSourceId());
|
||||
if (spell != null) {
|
||||
Permanent firstTarget = getPermanentFromFirstTarget(spell.getSpellAbility(), game);
|
||||
if (firstTarget != null) {
|
||||
int power = firstTarget.getPower().getValue();
|
||||
// overwrite the filter with the power predicate
|
||||
filter = new FilterCreaturePermanent("creature with power less than " + power);
|
||||
filter.add(new PowerPredicate(ComparisonType.FEWER_THAN, power));
|
||||
Set<UUID> possibleTargets = new HashSet<>();
|
||||
|
||||
Permanent firstPermanent = game.getPermanent(source.getFirstTarget());
|
||||
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) {
|
||||
if (firstPermanent == null) {
|
||||
// playable or first target not yet selected
|
||||
// use all
|
||||
possibleTargets.add(permanent.getId());
|
||||
} else {
|
||||
// real
|
||||
// filter by power
|
||||
if (firstPermanent.getPower().getValue() > permanent.getPower().getValue()) {
|
||||
possibleTargets.add(permanent.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.possibleTargets(sourceControllerId, source, game);
|
||||
}
|
||||
possibleTargets.removeIf(id -> firstPermanent != null && firstPermanent.getId().equals(id));
|
||||
|
||||
private Permanent getPermanentFromFirstTarget(Ability source, Game game) {
|
||||
Permanent firstTarget = null;
|
||||
if (source.getTargets().size() == 2) {
|
||||
firstTarget = game.getPermanent(source.getTargets().get(0).getFirstTarget());
|
||||
}
|
||||
return firstTarget;
|
||||
return keepValidPossibleTargets(possibleTargets, sourceControllerId, source, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -52,7 +52,8 @@ public final class OKagachiVengefulKami extends CardImpl {
|
|||
ability.addTarget(new TargetPermanent(filter));
|
||||
ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
|
||||
ability.withInterveningIf(KagachiVengefulKamiCondition.instance);
|
||||
this.addAbility(ability);
|
||||
|
||||
this.addAbility(ability, new OKagachiVengefulKamiWatcher());
|
||||
}
|
||||
|
||||
private OKagachiVengefulKami(final OKagachiVengefulKami card) {
|
||||
|
|
|
|||
|
|
@ -9,12 +9,12 @@ import mage.abilities.keyword.EquipAbility;
|
|||
import mage.abilities.keyword.TrampleAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.AttachmentType;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.ComparisonType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.*;
|
||||
import mage.filter.common.FilterControlledCreaturePermanent;
|
||||
import mage.filter.common.FilterCreatureCard;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.filter.predicate.mageobject.PowerPredicate;
|
||||
import mage.target.TargetCard;
|
||||
import mage.target.TargetPermanent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
|
@ -24,7 +24,7 @@ import java.util.UUID;
|
|||
*/
|
||||
public final class ONaginata extends CardImpl {
|
||||
|
||||
private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("creature with power 3 or greater");
|
||||
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with power 3 or greater");
|
||||
|
||||
static {
|
||||
filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 2));
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import mage.cards.CardSetInfo;
|
|||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
|
|
@ -81,7 +82,7 @@ class OildeepGearhulkEffect extends OneShotEffect {
|
|||
}
|
||||
|
||||
controller.lookAtCards(targetPlayer.getName() + " Hand", targetPlayer.getHand(), game);
|
||||
TargetCard chosenCard = new TargetCardInHand(0, 1, new FilterCard("card to discard"));
|
||||
TargetCard chosenCard = new TargetCard(0, 1, Zone.HAND, new FilterCard("card to discard"));
|
||||
if (!controller.choose(Outcome.Discard, targetPlayer.getHand(), chosenCard, source, game)) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -119,8 +119,8 @@ class OrcusPrinceOfUndeathTarget extends TargetCardInYourGraveyard {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) {
|
||||
return super.canTarget(controllerId, id, source, game)
|
||||
public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) {
|
||||
return super.canTarget(playerId, id, source, game)
|
||||
&& CardUtil.checkCanTargetTotalValueLimit(
|
||||
this.getTargets(), id, MageObject::getManaValue, xValue, game);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -101,8 +101,8 @@ class PairODiceLostTarget extends TargetCardInYourGraveyard {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) {
|
||||
return super.canTarget(controllerId, id, source, game)
|
||||
public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) {
|
||||
return super.canTarget(playerId, id, source, game)
|
||||
&& CardUtil.checkCanTargetTotalValueLimit(
|
||||
this.getTargets(), id, MageObject::getManaValue, xValue, game);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,8 +58,8 @@ class PatchUpTarget extends TargetCardInYourGraveyard {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) {
|
||||
return super.canTarget(controllerId, id, source, game)
|
||||
public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) {
|
||||
return super.canTarget(playerId, id, source, game)
|
||||
&& CardUtil.checkCanTargetTotalValueLimit(
|
||||
this.getTargets(), id, MageObject::getManaValue, 3, game);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ class PhenomenonInvestigatorsReturnCost extends CostImpl {
|
|||
|
||||
@Override
|
||||
public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) {
|
||||
return this.getTargets().canChoose(controllerId, source, game);
|
||||
return canChooseOrAlreadyChosen(ability, source, controllerId, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -94,8 +94,8 @@ class PhoenixWardenOfFireTarget extends TargetCardInYourGraveyard {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) {
|
||||
return super.canTarget(controllerId, id, source, game)
|
||||
public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) {
|
||||
return super.canTarget(playerId, id, source, game)
|
||||
&& CardUtil.checkCanTargetTotalValueLimit(
|
||||
this.getTargets(), id, MageObject::getManaValue, 6, game
|
||||
);
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ class PrimordialMistCost extends CostImpl {
|
|||
|
||||
@Override
|
||||
public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) {
|
||||
return target.canChoose(controllerId, source, game);
|
||||
return target.canChooseOrAlreadyChosen(controllerId, source, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -64,8 +64,8 @@ class ProteanHulkTarget extends TargetCardInLibrary {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) {
|
||||
return super.canTarget(controllerId, id, source, game)
|
||||
public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) {
|
||||
return super.canTarget(playerId, id, source, game)
|
||||
&& CardUtil.checkCanTargetTotalValueLimit(
|
||||
this.getTargets(), id, MageObject::getManaValue, 6, game);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,36 +1,36 @@
|
|||
package mage.cards.p;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.common.ExileTargetEffect;
|
||||
import mage.abilities.keyword.MonstrosityAbility;
|
||||
import mage.constants.SubType;
|
||||
import mage.abilities.keyword.FlyingAbility;
|
||||
import mage.abilities.keyword.MonstrosityAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.common.FilterArtifactOrEnchantmentPermanent;
|
||||
import mage.game.Controllable;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.target.TargetPermanent;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Jmlundeen
|
||||
*/
|
||||
public final class ProtectorOfTheWastes extends CardImpl {
|
||||
|
||||
public ProtectorOfTheWastes(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}{W}");
|
||||
|
||||
|
||||
this.subtype.add(SubType.DRAGON);
|
||||
this.power = new MageInt(5);
|
||||
this.toughness = new MageInt(5);
|
||||
|
|
@ -76,36 +76,19 @@ class ProtectorOfTheWastesTarget extends TargetPermanent {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID id, Ability source, Game game) {
|
||||
if (!super.canTarget(id, source, game)) {
|
||||
return false;
|
||||
}
|
||||
Permanent permanent = game.getPermanent(id);
|
||||
if (permanent == null) {
|
||||
return false;
|
||||
}
|
||||
return this.getTargets().stream()
|
||||
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
|
||||
Set<UUID> possibleTargets = super.possibleTargets(sourceControllerId, source, game);
|
||||
|
||||
Set<UUID> usedControllers = this.getTargets().stream()
|
||||
.map(game::getPermanent)
|
||||
.filter(Objects::nonNull)
|
||||
.noneMatch(perm -> !perm.getId().equals(permanent.getId())
|
||||
&& perm.isControlledBy(permanent.getControllerId()));
|
||||
}
|
||||
.map(Controllable::getControllerId)
|
||||
.collect(Collectors.toSet());
|
||||
possibleTargets.removeIf(id -> {
|
||||
Permanent permanent = game.getPermanent(id);
|
||||
return permanent == null || usedControllers.contains(permanent.getControllerId());
|
||||
});
|
||||
|
||||
@Override
|
||||
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
|
||||
Set<UUID> possibleTargets = new HashSet<>();
|
||||
MageObject targetSource = game.getObject(source);
|
||||
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) {
|
||||
boolean validTarget = this.getTargets().stream()
|
||||
.map(game::getPermanent)
|
||||
.filter(Objects::nonNull)
|
||||
.noneMatch(perm -> !perm.getId().equals(permanent.getId()) && perm.isControlledBy(permanent.getControllerId()));
|
||||
if (validTarget) {
|
||||
if (notTarget || permanent.canBeTargetedBy(targetSource, sourceControllerId, source, game)) {
|
||||
possibleTargets.add(permanent.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
return possibleTargets;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,18 @@
|
|||
|
||||
package mage.cards.p;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
|
||||
import mage.abilities.effects.common.continuous.ExchangeControlTargetEffect;
|
||||
import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.TargetController;
|
||||
import mage.filter.predicate.Predicates;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.target.TargetPermanent;
|
||||
import mage.target.common.TargetControlledPermanent;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
|
@ -33,7 +30,7 @@ public final class PucasMischief extends CardImpl {
|
|||
|
||||
// At the beginning of your upkeep, you may exchange control of target nonland permanent you control and target nonland permanent an opponent controls with an equal or lesser converted mana cost.
|
||||
Ability ability = new BeginningOfUpkeepTriggeredAbility(new ExchangeControlTargetEffect(Duration.EndOfGame, rule, false, true), true);
|
||||
ability.addTarget(new TargetControlledPermanentWithCMCGreaterOrLessThanOpponentPermanent());
|
||||
ability.addTarget(new TargetPermanent(StaticFilters.FILTER_CONTROLLED_PERMANENT_NON_LAND));
|
||||
ability.addTarget(new PucasMischiefSecondTarget());
|
||||
this.addAbility(ability);
|
||||
|
||||
|
|
@ -49,89 +46,53 @@ public final class PucasMischief extends CardImpl {
|
|||
}
|
||||
}
|
||||
|
||||
class TargetControlledPermanentWithCMCGreaterOrLessThanOpponentPermanent extends TargetControlledPermanent {
|
||||
|
||||
public TargetControlledPermanentWithCMCGreaterOrLessThanOpponentPermanent() {
|
||||
super();
|
||||
this.filter = this.filter.copy();
|
||||
filter.add(Predicates.not(CardType.LAND.getPredicate()));
|
||||
withTargetName("nonland permanent you control");
|
||||
}
|
||||
|
||||
private TargetControlledPermanentWithCMCGreaterOrLessThanOpponentPermanent(final TargetControlledPermanentWithCMCGreaterOrLessThanOpponentPermanent target) {
|
||||
super(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
|
||||
Set<UUID> possibleTargets = new HashSet<>();
|
||||
MageObject targetSource = game.getObject(source);
|
||||
if (targetSource != null) {
|
||||
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) {
|
||||
if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, source, game)) {
|
||||
possibleTargets.add(permanent.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
return possibleTargets;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TargetControlledPermanentWithCMCGreaterOrLessThanOpponentPermanent copy() {
|
||||
return new TargetControlledPermanentWithCMCGreaterOrLessThanOpponentPermanent(this);
|
||||
}
|
||||
}
|
||||
|
||||
class PucasMischiefSecondTarget extends TargetPermanent {
|
||||
|
||||
private Permanent firstTarget = null;
|
||||
|
||||
public PucasMischiefSecondTarget() {
|
||||
super();
|
||||
this.filter = this.filter.copy();
|
||||
filter.add(TargetController.OPPONENT.getControllerPredicate());
|
||||
filter.add(Predicates.not(CardType.LAND.getPredicate()));
|
||||
super(StaticFilters.FILTER_OPPONENTS_PERMANENT_NON_LAND);
|
||||
withTargetName("permanent an opponent controls with an equal or lesser mana value");
|
||||
}
|
||||
|
||||
private PucasMischiefSecondTarget(final PucasMischiefSecondTarget target) {
|
||||
super(target);
|
||||
this.firstTarget = target.firstTarget;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID id, Ability source, Game game) {
|
||||
if (super.canTarget(id, source, game)) {
|
||||
Permanent target1 = game.getPermanent(source.getFirstTarget());
|
||||
Permanent opponentPermanent = game.getPermanent(id);
|
||||
if (target1 != null && opponentPermanent != null) {
|
||||
return target1.getManaValue() >= opponentPermanent.getManaValue();
|
||||
}
|
||||
Permanent ownPermanent = game.getPermanent(source.getFirstTarget());
|
||||
Permanent possiblePermanent = game.getPermanent(id);
|
||||
if (ownPermanent == null || possiblePermanent == null) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
return super.canTarget(id, source, game) && ownPermanent.getManaValue() >= possiblePermanent.getManaValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
|
||||
Set<UUID> possibleTargets = new HashSet<>();
|
||||
if (firstTarget != null) {
|
||||
MageObject targetSource = game.getObject(source);
|
||||
if (targetSource != null) {
|
||||
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) {
|
||||
if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, source, game)) {
|
||||
if (firstTarget.getManaValue() >= permanent.getManaValue()) {
|
||||
possibleTargets.add(permanent.getId());
|
||||
}
|
||||
}
|
||||
|
||||
Permanent ownPermanent = game.getPermanent(source.getFirstTarget());
|
||||
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) {
|
||||
if (ownPermanent == null) {
|
||||
// playable or first target not yet selected
|
||||
// use all
|
||||
possibleTargets.add(permanent.getId());
|
||||
} else {
|
||||
// real
|
||||
// filter by cmc
|
||||
if (ownPermanent.getManaValue() >= permanent.getManaValue()) {
|
||||
possibleTargets.add(permanent.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
return possibleTargets;
|
||||
possibleTargets.removeIf(id -> ownPermanent != null && ownPermanent.getId().equals(id));
|
||||
|
||||
return keepValidPossibleTargets(possibleTargets, sourceControllerId, source, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean chooseTarget(Outcome outcome, UUID playerId, Ability source, Game game) {
|
||||
firstTarget = game.getPermanent(source.getFirstTarget());
|
||||
// AI hint with better outcome
|
||||
return super.chooseTarget(Outcome.GainControl, playerId, source, game);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -109,26 +109,11 @@ class QueenKaylaBinKroogTarget extends TargetCard {
|
|||
return new QueenKaylaBinKroogTarget(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID playerId, UUID id, Ability ability, Game game) {
|
||||
if (!super.canTarget(playerId, id, ability, game)) {
|
||||
return false;
|
||||
}
|
||||
Card card = game.getCard(id);
|
||||
return card != null && 1 <= card.getManaValue() && card.getManaValue() <= 3 && this
|
||||
.getTargets()
|
||||
.stream()
|
||||
.map(game::getCard)
|
||||
.filter(Objects::nonNull)
|
||||
.mapToInt(MageObject::getManaValue)
|
||||
.noneMatch(x -> card.getManaValue() == x);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
|
||||
Set<UUID> possibleTargets = super.possibleTargets(sourceControllerId, source, game);
|
||||
Set<Integer> manaValues = this
|
||||
|
||||
Set<Integer> usedManaValues = this
|
||||
.getTargets()
|
||||
.stream()
|
||||
.map(game::getCard)
|
||||
|
|
@ -137,8 +122,9 @@ class QueenKaylaBinKroogTarget extends TargetCard {
|
|||
.collect(Collectors.toSet());
|
||||
possibleTargets.removeIf(uuid -> {
|
||||
Card card = game.getCard(uuid);
|
||||
return card != null && manaValues.contains(card.getManaValue());
|
||||
return card == null || usedManaValues.contains(card.getManaValue());
|
||||
});
|
||||
|
||||
return possibleTargets;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,8 +58,8 @@ class RaiseTheDraugrTarget extends TargetCardInYourGraveyard {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) {
|
||||
if (!super.canTarget(controllerId, id, source, game)) {
|
||||
public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) {
|
||||
if (!super.canTarget(playerId, id, source, game)) {
|
||||
return false;
|
||||
}
|
||||
if (getTargets().isEmpty()) {
|
||||
|
|
|
|||
|
|
@ -82,8 +82,8 @@ class RampagingYaoGuaiTarget extends TargetPermanent {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) {
|
||||
return super.canTarget(controllerId, id, source, game)
|
||||
public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) {
|
||||
return super.canTarget(playerId, id, source, game)
|
||||
&& CardUtil.checkCanTargetTotalValueLimit(
|
||||
this.getTargets(), id, MageObject::getManaValue, GetXValue.instance.calculate(game, source, null), game);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ class RasputinDreamweaverWatcher extends Watcher {
|
|||
filter.add(TappedPredicate.UNTAPPED);
|
||||
}
|
||||
|
||||
private final Set<UUID> startedUntapped = new HashSet<>(0);
|
||||
private final Set<UUID> startedUntapped = new HashSet<>();
|
||||
|
||||
RasputinDreamweaverWatcher() {
|
||||
super(WatcherScope.GAME);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package mage.cards.r;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.TransformIntoSourceTriggeredAbility;
|
||||
import mage.abilities.common.WerewolfBackTriggeredAbility;
|
||||
|
|
@ -15,13 +14,11 @@ import mage.constants.SubType;
|
|||
import mage.filter.StaticFilters;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.stack.StackObject;
|
||||
import mage.players.Player;
|
||||
import mage.target.TargetPermanent;
|
||||
import mage.target.common.TargetOpponentOrPlaneswalker;
|
||||
import mage.target.targetpointer.EachTargetPointer;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
|
|
@ -100,54 +97,30 @@ class RavagerOfTheFellsEffect extends OneShotEffect {
|
|||
class RavagerOfTheFellsTarget extends TargetPermanent {
|
||||
|
||||
RavagerOfTheFellsTarget() {
|
||||
super(0, 1, StaticFilters.FILTER_PERMANENT_CREATURE, false);
|
||||
super(0, 1, StaticFilters.FILTER_PERMANENT_CREATURE);
|
||||
}
|
||||
|
||||
private RavagerOfTheFellsTarget(final RavagerOfTheFellsTarget target) {
|
||||
super(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID id, Ability source, Game game) {
|
||||
Player player = game.getPlayerOrPlaneswalkerController(source.getFirstTarget());
|
||||
if (player == null) {
|
||||
return false;
|
||||
}
|
||||
UUID firstTarget = player.getId();
|
||||
Permanent permanent = game.getPermanent(id);
|
||||
if (firstTarget != null && permanent != null && permanent.isControlledBy(firstTarget)) {
|
||||
return super.canTarget(id, source, game);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
|
||||
Set<UUID> availablePossibleTargets = super.possibleTargets(sourceControllerId, source, game);
|
||||
Set<UUID> possibleTargets = new HashSet<>();
|
||||
MageObject object = game.getObject(source);
|
||||
Set<UUID> possibleTargets = super.possibleTargets(sourceControllerId, source, game);
|
||||
|
||||
for (StackObject item : game.getState().getStack()) {
|
||||
if (item.getId().equals(source.getSourceId())) {
|
||||
object = item;
|
||||
}
|
||||
if (item.getSourceId().equals(source.getSourceId())) {
|
||||
object = item;
|
||||
}
|
||||
Player needPlayer = game.getPlayerOrPlaneswalkerController(source.getFirstTarget());
|
||||
if (needPlayer == null) {
|
||||
// playable or not selected - use any
|
||||
} else {
|
||||
// filter by controller
|
||||
possibleTargets.removeIf(id -> {
|
||||
Permanent permanent = game.getPermanent(id);
|
||||
return permanent == null
|
||||
|| permanent.getId().equals(source.getFirstTarget())
|
||||
|| !permanent.isControlledBy(needPlayer.getId());
|
||||
});
|
||||
}
|
||||
|
||||
if (object instanceof StackObject) {
|
||||
UUID playerId = ((StackObject) object).getStackAbility().getFirstTarget();
|
||||
Player player = game.getPlayerOrPlaneswalkerController(playerId);
|
||||
if (player != null) {
|
||||
for (UUID targetId : availablePossibleTargets) {
|
||||
Permanent permanent = game.getPermanent(targetId);
|
||||
if (permanent != null && permanent.isControlledBy(player.getId())) {
|
||||
possibleTargets.add(targetId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return possibleTargets;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ class ReapIntellectEffect extends OneShotEffect {
|
|||
int xCost = Math.min(CardUtil.getSourceCostsTag(game, source, "X", 0), targetPlayer.getHand().size());
|
||||
TargetCard target = new TargetCard(0, xCost, Zone.HAND, filterNonLands);
|
||||
target.withNotTarget(true);
|
||||
controller.chooseTarget(Outcome.Benefit, targetPlayer.getHand(), target, source, game);
|
||||
controller.choose(Outcome.Benefit, targetPlayer.getHand(), target, source, game);
|
||||
for (UUID cardId : target.getTargets()) {
|
||||
Card chosenCard = game.getCard(cardId);
|
||||
if (chosenCard != null) {
|
||||
|
|
|
|||
|
|
@ -1,20 +1,15 @@
|
|||
|
||||
package mage.cards.r;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.common.ExileTargetEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.constants.TargetController;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.filter.predicate.other.DamagedPlayerThisTurnPredicate;
|
||||
import mage.target.TargetPermanent;
|
||||
import mage.watchers.common.PlayerDamagedBySourceWatcher;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
|
|
@ -22,12 +17,18 @@ import java.util.UUID;
|
|||
*/
|
||||
public final class Reciprocate extends CardImpl {
|
||||
|
||||
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature that dealt damage to you this turn");
|
||||
|
||||
static {
|
||||
filter.add(new DamagedPlayerThisTurnPredicate(TargetController.YOU));
|
||||
}
|
||||
|
||||
public Reciprocate(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{W}");
|
||||
|
||||
// Exile target creature that dealt damage to you this turn.
|
||||
this.getSpellAbility().addEffect(new ExileTargetEffect());
|
||||
this.getSpellAbility().addTarget(new ReciprocateTarget());
|
||||
this.getSpellAbility().addTarget(new TargetPermanent(filter));
|
||||
}
|
||||
|
||||
private Reciprocate(final Reciprocate card) {
|
||||
|
|
@ -40,66 +41,3 @@ public final class Reciprocate extends CardImpl {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
class ReciprocateTarget extends TargetPermanent {
|
||||
|
||||
public ReciprocateTarget() {
|
||||
super(1, 1, StaticFilters.FILTER_PERMANENT_CREATURE, false);
|
||||
targetName = "creature that dealt damage to you this turn";
|
||||
}
|
||||
|
||||
private ReciprocateTarget(final ReciprocateTarget target) {
|
||||
super(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID id, Ability source, Game game) {
|
||||
PlayerDamagedBySourceWatcher watcher = game.getState().getWatcher(PlayerDamagedBySourceWatcher.class, source.getControllerId());
|
||||
if (watcher != null && watcher.hasSourceDoneDamage(id, game)) {
|
||||
return super.canTarget(id, source, game);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
|
||||
Set<UUID> availablePossibleTargets = super.possibleTargets(sourceControllerId, source, game);
|
||||
Set<UUID> possibleTargets = new HashSet<>();
|
||||
PlayerDamagedBySourceWatcher watcher = game.getState().getWatcher(PlayerDamagedBySourceWatcher.class, sourceControllerId);
|
||||
for (UUID targetId : availablePossibleTargets) {
|
||||
Permanent permanent = game.getPermanent(targetId);
|
||||
if (permanent != null && watcher != null && watcher.hasSourceDoneDamage(targetId, game)) {
|
||||
possibleTargets.add(targetId);
|
||||
}
|
||||
}
|
||||
return possibleTargets;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canChoose(UUID sourceControllerId, Ability source, Game game) {
|
||||
int remainingTargets = this.minNumberOfTargets - targets.size();
|
||||
if (remainingTargets == 0) {
|
||||
return true;
|
||||
}
|
||||
int count = 0;
|
||||
MageObject targetSource = game.getObject(source);
|
||||
if (targetSource != null) {
|
||||
PlayerDamagedBySourceWatcher watcher = game.getState().getWatcher(PlayerDamagedBySourceWatcher.class, sourceControllerId);
|
||||
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) {
|
||||
if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, source, game)
|
||||
&& watcher != null && watcher.hasSourceDoneDamage(permanent.getId(), game)) {
|
||||
count++;
|
||||
if (count >= remainingTargets) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReciprocateTarget copy() {
|
||||
return new ReciprocateTarget(this);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import mage.cards.CardImpl;
|
|||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.counters.CounterType;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.game.Game;
|
||||
|
|
@ -68,7 +69,7 @@ class ReckonerShakedownEffect extends OneShotEffect {
|
|||
return false;
|
||||
}
|
||||
player.revealCards(source, player.getHand(), game);
|
||||
TargetCard target = new TargetCardInHand(0, 1, StaticFilters.FILTER_CARD_A_NON_LAND);
|
||||
TargetCard target = new TargetCard(0, 1, Zone.HAND, StaticFilters.FILTER_CARD_A_NON_LAND);
|
||||
controller.choose(Outcome.Discard, player.getHand(), target, source, game);
|
||||
Card card = game.getCard(target.getFirstTarget());
|
||||
if (card != null) {
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ class RetetherEffect extends OneShotEffect {
|
|||
for (Ability ability : aura.getAbilities()) {
|
||||
if (ability instanceof SpellAbility) {
|
||||
for (Target abilityTarget : ability.getTargets()) {
|
||||
if (abilityTarget.possibleTargets(controller.getId(), game).contains(permanent.getId())) {
|
||||
if (abilityTarget.possibleTargets(controller.getId(), source, game).contains(permanent.getId())) {
|
||||
target = abilityTarget.copy();
|
||||
break auraLegalitySearch;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,8 +58,8 @@ class ReturnFromExtinctionTarget extends TargetCardInYourGraveyard {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) {
|
||||
if (!super.canTarget(controllerId, id, source, game)) {
|
||||
public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) {
|
||||
if (!super.canTarget(playerId, id, source, game)) {
|
||||
return false;
|
||||
}
|
||||
if (getTargets().isEmpty()) {
|
||||
|
|
|
|||
|
|
@ -61,8 +61,8 @@ class ReunionOfTheHouseTarget extends TargetCardInYourGraveyard {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) {
|
||||
return super.canTarget(controllerId, id, source, game)
|
||||
public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) {
|
||||
return super.canTarget(playerId, id, source, game)
|
||||
&& CardUtil.checkCanTargetTotalValueLimit(
|
||||
this.getTargets(), id, m -> m.getPower().getValue(), 10, game);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import mage.cards.CardSetInfo;
|
|||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
|
|
@ -82,7 +83,7 @@ class RevealingEyeEffect extends OneShotEffect {
|
|||
if (opponent.getHand().count(StaticFilters.FILTER_CARD_NON_LAND, game) < 1) {
|
||||
return true;
|
||||
}
|
||||
TargetCard target = new TargetCardInHand(0, 1, StaticFilters.FILTER_CARD_NON_LAND);
|
||||
TargetCard target = new TargetCard(0, 1, Zone.HAND, StaticFilters.FILTER_CARD_NON_LAND);
|
||||
controller.choose(outcome, opponent.getHand(), target, source, game);
|
||||
Card card = game.getCard(target.getFirstTarget());
|
||||
if (card == null) {
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ class RevivalExperimentTarget extends TargetCardInYourGraveyard {
|
|||
@Override
|
||||
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
|
||||
Set<UUID> possibleTargets = super.possibleTargets(sourceControllerId, source, game);
|
||||
possibleTargets.removeIf(uuid -> !this.canTarget(sourceControllerId, uuid, null, game));
|
||||
possibleTargets.removeIf(uuid -> !this.canTarget(sourceControllerId, uuid, source, game));
|
||||
return possibleTargets;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ class RiftElementalCost extends CostImpl {
|
|||
@Override
|
||||
public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) {
|
||||
Target target = new TargetPermanentOrSuspendedCard(filter, true);
|
||||
return target.canChoose(controllerId, source, game);
|
||||
return target.canChooseOrAlreadyChosen(controllerId, source, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -90,8 +90,8 @@ class RivalsDuelTarget extends TargetPermanent {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) {
|
||||
if (!super.canTarget(controllerId, id, source, game)) {
|
||||
public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) {
|
||||
if (!super.canTarget(playerId, id, source, game)) {
|
||||
return false;
|
||||
}
|
||||
Permanent creature = game.getPermanent(id);
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ class RoguesGalleryTarget extends TargetCardInYourGraveyard {
|
|||
@Override
|
||||
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
|
||||
Set<UUID> possibleTargets = super.possibleTargets(sourceControllerId, source, game);
|
||||
possibleTargets.removeIf(uuid -> !this.canTarget(sourceControllerId, uuid, null, game));
|
||||
possibleTargets.removeIf(uuid -> !this.canTarget(sourceControllerId, uuid, source, game));
|
||||
return possibleTargets;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,8 +53,8 @@ class TargetPermanentsThatShareCardType extends TargetPermanent {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) {
|
||||
if (super.canTarget(controllerId, id, source, game)) {
|
||||
public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) {
|
||||
if (super.canTarget(playerId, id, source, game)) {
|
||||
if (!getTargets().isEmpty()) {
|
||||
Permanent targetOne = game.getPermanent(getTargets().get(0));
|
||||
Permanent targetTwo = game.getPermanent(id);
|
||||
|
|
|
|||
|
|
@ -59,8 +59,8 @@ class RunAwayTogetherTarget extends TargetPermanent {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) {
|
||||
if (!super.canTarget(controllerId, id, source, game)) {
|
||||
public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) {
|
||||
if (!super.canTarget(playerId, id, source, game)) {
|
||||
return false;
|
||||
}
|
||||
Permanent creature = game.getPermanent(id);
|
||||
|
|
|
|||
|
|
@ -96,8 +96,8 @@ class ScoutForSurvivorsTarget extends TargetCardInYourGraveyard {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) {
|
||||
return super.canTarget(controllerId, id, source, game)
|
||||
public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) {
|
||||
return super.canTarget(playerId, id, source, game)
|
||||
&& CardUtil.checkCanTargetTotalValueLimit(
|
||||
this.getTargets(), id, MageObject::getManaValue, 3, game
|
||||
);
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue