foul-magics/Mage.Sets/src/mage/cards/m/ModifyMemory.java
Oleg Agafonov c7a485b728 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;
2025-08-04 23:56:23 +04:00

105 lines
3.4 KiB
Java

package mage.cards.m;
import mage.abilities.Ability;
import mage.abilities.condition.Condition;
import mage.abilities.decorator.ConditionalOneShotEffect;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.continuous.ExchangeControlTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.filter.common.FilterCreaturePermanent;
import mage.game.Controllable;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.Target;
import mage.target.TargetPermanent;
import mage.target.targetpointer.EachTargetPointer;
import java.util.Collection;
import java.util.Objects;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class ModifyMemory extends CardImpl {
public ModifyMemory(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{U}");
// Exchange control of two target creatures controlled by different players. If you control neither creature, draw three cards.
this.getSpellAbility().addEffect(new ExchangeControlTargetEffect(
Duration.Custom, "exchange control of two target creatures controlled by different players"
).setTargetPointer(new EachTargetPointer()));
this.getSpellAbility().addEffect(new ConditionalOneShotEffect(
new DrawCardSourceControllerEffect(3), ModifyMemoryCondition.instance,
"If you control neither creature, draw three cards"
));
this.getSpellAbility().addTarget(new ModifyMemoryTarget());
}
private ModifyMemory(final ModifyMemory card) {
super(card);
}
@Override
public ModifyMemory copy() {
return new ModifyMemory(this);
}
}
enum ModifyMemoryCondition implements Condition {
instance;
@Override
public boolean apply(Game game, Ability source) {
return source
.getTargets()
.stream()
.map(Target::getTargets)
.flatMap(Collection::stream)
.map(game::getPermanentOrLKIBattlefield)
.filter(Objects::nonNull)
.map(Controllable::getControllerId)
.noneMatch(source::isControlledBy);
}
}
class ModifyMemoryTarget extends TargetPermanent {
private static final FilterCreaturePermanent filter
= new FilterCreaturePermanent("creatures controlled by different players");
ModifyMemoryTarget() {
super(2, 2, filter, false);
}
private ModifyMemoryTarget(final ModifyMemoryTarget target) {
super(target);
}
@Override
public ModifyMemoryTarget copy() {
return new ModifyMemoryTarget(this);
}
@Override
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);
if (creature == null) {
return false;
}
return this.getTargets()
.stream()
.map(game::getPermanent)
.filter(Objects::nonNull)
.noneMatch(permanent -> !creature.getId().equals(permanent.getId())
&& creature.isControlledBy(permanent.getControllerId())
);
}
}