multiple changes:

* refactor: improved target pointer init code and logic, added docs and runtime checks;
* game: fixed miss or wrong init calls in some continuous effects;
* game: fixed wrong usage of target pointers (miss copy code, miss npe checks);
This commit is contained in:
Oleg Agafonov 2024-02-18 15:05:05 +04:00
parent b2aa4ecc08
commit 78612ddc91
115 changed files with 466 additions and 355 deletions

View file

@ -64,8 +64,8 @@ class AuriokReplicaEffect extends PreventionEffectImpl {
@Override
public void init(Ability source, Game game) {
this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game);
super.init(source, game);
this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game);
}
@Override

View file

@ -14,6 +14,7 @@ import mage.constants.*;
import mage.game.Game;
import mage.players.Player;
import java.util.Objects;
import java.util.UUID;
/**
@ -74,8 +75,9 @@ class BackdraftHellkiteEffect extends ContinuousEffectImpl {
}
player.getGraveyard()
.stream()
.map((cardId) -> game.getCard(cardId))
.filter(card1 -> card1.isInstantOrSorcery(game))
.map(game::getCard)
.filter(Objects::nonNull)
.filter(card -> card.isInstantOrSorcery(game))
.forEachOrdered(card -> affectedObjectList.add(new MageObjectReference(card, game)));
}

View file

@ -71,8 +71,8 @@ class BeaconOfDestinyEffect extends RedirectionEffect {
@Override
public void init(Ability source, Game game) {
this.damageSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game);
super.init(source, game);
this.damageSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game);
}
@Override

View file

@ -61,22 +61,22 @@ class BesmirchEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
if (game.getPermanent(source.getFirstTarget()) != null) {
TargetPointer target = new FixedTarget(source.getFirstTarget(), game);
TargetPointer blueprintTarget = new FixedTarget(source.getFirstTarget(), game);
// gain control
game.addEffect(new GainControlTargetEffect(Duration.EndOfTurn)
.setTargetPointer(target), source);
.setTargetPointer(blueprintTarget.copy()), source);
// haste
game.addEffect(new GainAbilityTargetEffect(
HasteAbility.getInstance(), Duration.EndOfTurn
).setTargetPointer(target), source);
).setTargetPointer(blueprintTarget.copy()), source);
// goad
game.addEffect(new GoadTargetEffect().setTargetPointer(target), source);
game.addEffect(new GoadTargetEffect().setTargetPointer(blueprintTarget.copy()), source);
// untap
new UntapTargetEffect().setTargetPointer(target).apply(game, source);
new UntapTargetEffect().setTargetPointer(blueprintTarget.copy()).apply(game, source);
return true;
}

View file

@ -68,8 +68,8 @@ class BoneMaskEffect extends PreventionEffectImpl {
@Override
public void init(Ability source, Game game) {
this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game);
super.init(source, game);
this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game);
}
@Override

View file

@ -74,6 +74,7 @@ class ChoArrimAlchemistEffect extends PreventionEffectImpl {
@Override
public void init(Ability source, Game game) {
super.init(source, game);
this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game);
}

View file

@ -86,15 +86,17 @@ class CommandersPlateEffect extends ContinuousEffectImpl {
@Override
public void init(Ability source, Game game) {
super.init(source, game);
if (!affectedObjectsSet) {
return;
}
Permanent equipment = game.getPermanentOrLKIBattlefield(source.getSourceId());
if (equipment == null || equipment.getAttachedTo() == null) {
discard();
return;
}
this.setTargetPointer(new FixedTarget(equipment.getAttachedTo(), game));
super.init(source, game); // must call at the end due target pointer setup
}
@Override

View file

@ -71,6 +71,11 @@ class ConvincingMirageContinousEffect extends ContinuousEffectImpl {
public void init(Ability source, Game game) {
super.init(source, game);
SubType choice = SubType.byDescription((String) game.getState().getValue(source.getSourceId().toString() + ChooseBasicLandTypeEffect.VALUE_KEY));
if (choice == null) {
discard();
return;
}
switch (choice) {
case FOREST:
dependencyTypes.add(DependencyType.BecomeForest);

View file

@ -79,14 +79,14 @@ class CorpseDanceEffect extends OneShotEffect {
if (controller.moveCards(lastCreatureCard, Zone.BATTLEFIELD, source, game)) {
Permanent creature = game.getPermanent(lastCreatureCard.getId());
if (creature != null) {
FixedTarget fixedTarget = new FixedTarget(creature, game);
FixedTarget blueprintTarget = new FixedTarget(creature, game);
// Gains Haste
ContinuousEffect hasteEffect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn);
hasteEffect.setTargetPointer(fixedTarget);
hasteEffect.setTargetPointer(blueprintTarget.copy());
game.addEffect(hasteEffect, source);
// Exile it at end of turn
ExileTargetEffect exileEffect = new ExileTargetEffect(null, "", Zone.BATTLEFIELD);
exileEffect.setTargetPointer(fixedTarget);
exileEffect.setTargetPointer(blueprintTarget.copy());
DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect);
game.addDelayedTriggeredAbility(delayedAbility, source);
}

View file

@ -104,16 +104,16 @@ class CosmiumConfluenceEffect extends OneShotEffect {
}
controller.choose(outcome, target, source, game);
FixedTarget fixedTarget = new FixedTarget(target.getFirstTarget(), game);
FixedTarget blueprintTarget = new FixedTarget(target.getFirstTarget(), game);
new AddCountersTargetEffect(CounterType.P1P1.createInstance(3))
.setTargetPointer(fixedTarget)
.setTargetPointer(blueprintTarget.copy())
.apply(game, source);
ContinuousEffect effect = new BecomesCreatureTargetEffect(
new CreatureToken(0, 0, "0/0 Elemental creature with haste", SubType.ELEMENTAL)
.withAbility(HasteAbility.getInstance()),
false, true, Duration.Custom
);
effect.setTargetPointer(fixedTarget);
effect.setTargetPointer(blueprintTarget.copy());
game.addEffect(effect, source);
return true;
}

View file

@ -70,6 +70,7 @@ class DarkSpherePreventionEffect extends ReplacementEffectImpl {
@Override
public void init(Ability source, Game game) {
super.init(source, game);
this.targetSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game);
}

View file

@ -62,8 +62,8 @@ class DeflectingPalmEffect extends PreventionEffectImpl {
@Override
public void init(Ability source, Game game) {
this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game);
super.init(source, game);
this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game);
}
@Override

View file

@ -65,12 +65,16 @@ class DesperateGambitEffect extends PreventionEffectImpl {
@Override
public void init(Ability source, Game game) {
this.target.choose(Outcome.Benefit, source.getControllerId(), source.getSourceId(), source, game);
super.init(source, game);
Player you = game.getPlayer(source.getControllerId());
if(you != null) {
wonFlip = you.flipCoin(source, game, true);
super.init(source, game);
if (you == null) {
discard();
return;
}
this.target.choose(Outcome.Benefit, source.getControllerId(), source.getSourceId(), source, game);
this.wonFlip = you.flipCoin(source, game, true);
}
@Override

View file

@ -78,15 +78,15 @@ class DisplacedDinosaursEntersBattlefieldEffect extends ReplacementEffectImpl {
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
Permanent historic = ((EntersTheBattlefieldEvent) event).getTarget();
if (historic != null) {
TargetPointer historicTarget = new FixedTarget(historic.getId(), historic.getZoneChangeCounter(game) + 1);
TargetPointer blueprintTarget = new FixedTarget(historic.getId(), historic.getZoneChangeCounter(game) + 1);
ContinuousEffect creatureEffect = new AddCardTypeTargetEffect(Duration.Custom, CardType.CREATURE);
creatureEffect.setTargetPointer(historicTarget);
creatureEffect.setTargetPointer(blueprintTarget.copy());
game.addEffect(creatureEffect, source);
ContinuousEffect dinosaurEffect = new AddCardSubTypeTargetEffect(SubType.DINOSAUR, Duration.Custom);
dinosaurEffect.setTargetPointer(historicTarget);
dinosaurEffect.setTargetPointer(blueprintTarget.copy());
game.addEffect(dinosaurEffect, source);
ContinuousEffect sevenSevenEffect = new SetBasePowerToughnessTargetEffect(7, 7, Duration.Custom);
sevenSevenEffect.setTargetPointer(historicTarget);
sevenSevenEffect.setTargetPointer(blueprintTarget.copy());
game.addEffect(sevenSevenEffect, source);
}
return false;

View file

@ -1,6 +1,7 @@
package mage.cards.e;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
@ -23,6 +24,7 @@ import mage.target.targetpointer.FixedTargets;
import mage.target.targetpointer.TargetPointer;
import mage.util.CardUtil;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
@ -127,16 +129,16 @@ class ElrondOfWhiteCouncilEffect extends OneShotEffect {
}
// You gain control of each creature chosen this way, and they gain "This creature can't attack its owner."
TargetPointer pointer = new FixedTargets(chosenCreatures.stream().collect(Collectors.toList()), game);
TargetPointer blueprintTarget = new FixedTargets(new ArrayList<>(chosenCreatures), game);
game.addEffect(new GainControlTargetEffect(
Duration.WhileOnBattlefield
).setTargetPointer(pointer), source);
).setTargetPointer(blueprintTarget.copy()), source);
game.addEffect(new GainAbilityTargetEffect(
new SimpleStaticAbility(new CantAttackItsOwnerEffect()),
Duration.WhileOnBattlefield
).setTargetPointer(pointer), source);
).setTargetPointer(blueprintTarget.copy()), source);
// Need to process the control change.
game.getState().processAction(game);

View file

@ -95,6 +95,11 @@ class ElsewhereFlaskContinuousEffect extends ContinuousEffectImpl {
public void init(Ability source, Game game) {
super.init(source, game);
SubType choice = SubType.byDescription((String) game.getState().getValue(source.getSourceId().toString() + "_ElsewhereFlask"));
if (choice == null) {
discard();
return;
}
switch (choice) {
case FOREST:
dependencyTypes.add(DependencyType.BecomeForest);

View file

@ -59,8 +59,8 @@ class EyeForAnEyeEffect extends ReplacementEffectImpl {
@Override
public void init(Ability source, Game game) {
this.damageSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game);
super.init(source, game);
this.damageSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game);
}
@Override

View file

@ -54,9 +54,9 @@ class FecundityEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = (Permanent) game.getLastKnownInformation(this.getTargetPointer()
// Card can be moved again (e.g. commander replacement) so we need the row id from fixed target to check
.getFixedTarget(game, source).getTarget(), Zone.BATTLEFIELD);
// card can be moved again (e.g. commander replacement) so we need the row id from fixed target to check
// TODO: bugged with commander replacement effects?
Permanent permanent = (Permanent) game.getLastKnownInformation(this.getTargetPointer().getFirst(game, source), Zone.BATTLEFIELD);
if (permanent != null) {
Player controller = game.getPlayer(permanent.getControllerId());
if (controller != null) {

View file

@ -67,8 +67,8 @@ class GeneralsRegaliaEffect extends RedirectionEffect {
@Override
public void init(Ability source, Game game) {
this.damageSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game);
super.init(source, game);
this.damageSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game);
}
@Override

View file

@ -1,6 +1,5 @@
package mage.cards.g;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.DelayedTriggeredAbility;
@ -28,8 +27,9 @@ import mage.players.Player;
import mage.target.common.TargetCreaturePermanent;
import mage.target.targetpointer.FixedTarget;
import java.util.UUID;
/**
*
* @author noahg
*/
public final class GiantOyster extends CardImpl {
@ -103,23 +103,24 @@ class GiantOysterCreateDelayedTriggerEffects extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
Permanent oyster = game.getPermanent(source.getSourceId());
Permanent tappedCreature = game.getPermanent(source.getFirstTarget());
if (oyster != null && tappedCreature != null) {
Effect addCountersEffect = new AddCountersTargetEffect(CounterType.M1M1.createInstance(1));
addCountersEffect.setTargetPointer(getTargetPointer().getFixedTarget(game, source));
DelayedTriggeredAbility drawStepAbility = new AtTheBeginOfYourNextDrawStepDelayedTriggeredAbility(addCountersEffect, Duration.Custom, false);
drawStepAbility.setControllerId(source.getControllerId());
UUID drawStepAbilityUUID = game.addDelayedTriggeredAbility(drawStepAbility, source);
DelayedTriggeredAbility leaveUntapDelayedTriggeredAbility = new GiantOysterLeaveUntapDelayedTriggeredAbility(drawStepAbilityUUID);
leaveUntapDelayedTriggeredAbility.getEffects().get(0).setTargetPointer(new FixedTarget(tappedCreature, game));
game.addDelayedTriggeredAbility(leaveUntapDelayedTriggeredAbility, source);
return true;
}
Permanent oyster = game.getPermanent(source.getSourceId());
Permanent tappedCreature = game.getPermanent(source.getFirstTarget());
FixedTarget fixedTarget = getTargetPointer().getFirstAsFixedTarget(game, source);
if (controller == null || oyster == null || tappedCreature == null || fixedTarget == null) {
return false;
}
return false;
Effect addCountersEffect = new AddCountersTargetEffect(CounterType.M1M1.createInstance(1));
addCountersEffect.setTargetPointer(fixedTarget);
DelayedTriggeredAbility drawStepAbility = new AtTheBeginOfYourNextDrawStepDelayedTriggeredAbility(addCountersEffect, Duration.Custom, false);
drawStepAbility.setControllerId(source.getControllerId());
UUID drawStepAbilityUUID = game.addDelayedTriggeredAbility(drawStepAbility, source);
DelayedTriggeredAbility leaveUntapDelayedTriggeredAbility = new GiantOysterLeaveUntapDelayedTriggeredAbility(drawStepAbilityUUID);
leaveUntapDelayedTriggeredAbility.getEffects().get(0).setTargetPointer(new FixedTarget(tappedCreature, game));
game.addDelayedTriggeredAbility(leaveUntapDelayedTriggeredAbility, source);
return true;
}
}

View file

@ -66,7 +66,6 @@ class GiftOfFangsEffect extends ContinuousEffectImpl {
@Override
public void init(Ability source, Game game) {
super.init(source, game);
if (affectedObjectsSet) {
// Added boosts of activated or triggered abilities exist independent from the source they are created by
// so a continuous effect for the permanent itself with the attachment is created
@ -75,6 +74,8 @@ class GiftOfFangsEffect extends ContinuousEffectImpl {
this.setTargetPointer(new FixedTarget(equipment.getAttachedTo(), game.getState().getZoneChangeCounter(equipment.getAttachedTo())));
}
}
super.init(source, game); // must call at the end due target pointer setup
}
@Override

View file

@ -59,8 +59,15 @@ class GoblinPsychopathEffect extends ReplacementEffectImpl {
@Override
public void init(Ability source, Game game) {
this.wonFlip = game.getPlayer(source.getControllerId()).flipCoin(source, game, true);
super.init(source, game);
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
discard();
return;
}
this.wonFlip = controller.flipCoin(source, game, true);
}
@Override

View file

@ -69,12 +69,12 @@ class GoreVassalEffect extends RegenerateTargetEffect {
@Override
public void init(Ability source, Game game) {
super.init(source, game);
Permanent creature = game.getPermanent(source.getFirstTarget());
if (creature == null || creature.getToughness().getValue() < 1) {
this.discard();
return;
}
super.init(source, game);
}
}

View file

@ -67,10 +67,11 @@ class GuardDogsEffect extends PreventionEffectImpl {
@Override
public void init(Ability source, Game game) {
super.init(source, game);
this.controlledTarget = new TargetControlledPermanent();
this.controlledTarget.withNotTarget(true);
this.controlledTarget.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game);
super.init(source, game);
}

View file

@ -63,8 +63,8 @@ class HarmsWayPreventDamageTargetEffect extends RedirectionEffect {
@Override
public void init(Ability source, Game game) {
this.damageSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game);
super.init(source, game);
this.damageSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game);
}
@Override

View file

@ -76,6 +76,7 @@ class HazduhrTheAbbotRedirectDamageEffect extends RedirectionEffect {
@Override
public void init(Ability source, Game game) {
super.init(source, game);
amountToRedirect = source.getManaCostsToPay().getX();
}

View file

@ -62,6 +62,7 @@ class HealingGraceEffect extends PreventionEffectImpl {
@Override
public void init(Ability source, Game game) {
super.init(source, game);
this.targetSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game);
// be sure to note the target source's zcc, etc, if able.
if (targetSource.getFirstTarget() != null) {

View file

@ -79,6 +79,7 @@ class HisokasGuardGainAbilityTargetEffect extends ContinuousEffectImpl {
@Override
public void init(Ability source, Game game) {
super.init(source, game);
// remember the guarded creature
Permanent guardedCreature = game.getPermanent(this.getTargetPointer().getFirst(game, source));
Permanent hisokasGuard = game.getPermanent(source.getSourceId());

View file

@ -78,6 +78,7 @@ class HoardSmelterEffect extends ContinuousEffectImpl {
@Override
public void init(Ability source, Game game) {
super.init(source, game);
Card targeted = game.getCard(source.getFirstTarget());
if (targeted != null) {
costValue = targeted.getManaValue();

View file

@ -82,13 +82,13 @@ class HuntingWildsEffect extends OneShotEffect {
if (sourceEffect instanceof SearchLibraryPutInPlayEffect) {
Cards foundCards = new CardsImpl(((SearchLibraryPutInPlayEffect) sourceEffect).getTargets());
if (!foundCards.isEmpty()) {
FixedTargets fixedTargets = new FixedTargets(foundCards, game);
FixedTargets blueprintTarget = new FixedTargets(foundCards, game);
UntapTargetEffect untapEffect = new UntapTargetEffect();
untapEffect.setTargetPointer(fixedTargets);
untapEffect.setTargetPointer(blueprintTarget.copy());
untapEffect.apply(game, source);
BecomesCreatureTargetEffect becomesCreatureEffect = new BecomesCreatureTargetEffect(new HuntingWildsToken(), false, true, Duration.Custom);
becomesCreatureEffect.setTargetPointer(fixedTargets);
becomesCreatureEffect.setTargetPointer(blueprintTarget.copy());
game.addEffect(becomesCreatureEffect, source);
}
return true;

View file

@ -64,6 +64,8 @@ class IllicitAuctionEffect extends GainControlTargetEffect {
@Override
public void init(Ability source, Game game) {
super.init(source, game);
Player controller = game.getPlayer(source.getControllerId());
Permanent targetCreature = game.getPermanent(source.getFirstTarget());
if (controller != null && targetCreature != null) {
@ -108,7 +110,6 @@ class IllicitAuctionEffect extends GainControlTargetEffect {
winner.loseLife(highBid, game, source, false);
super.controllingPlayerId = winner.getId();
}
super.init(source, game);
}
}

View file

@ -57,8 +57,8 @@ class ImpulsiveManeuversEffect extends PreventionEffectImpl {
@Override
public void init(Ability source, Game game) {
this.wonFlip = game.getPlayer(source.getControllerId()).flipCoin(source, game, true);
super.init(source, game);
this.wonFlip = game.getPlayer(source.getControllerId()).flipCoin(source, game, true);
}
@Override

View file

@ -70,6 +70,7 @@ class JadeMonolithRedirectionEffect extends ReplacementEffectImpl {
@Override
public void init(Ability source, Game game) {
super.init(source, game);
this.targetSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game);
}

View file

@ -75,6 +75,7 @@ class JuxtaposeEffect extends ContinuousEffectImpl {
@Override
public void init(Ability source, Game game) {
super.init(source, game);
Player you = game.getPlayer(source.getControllerId());
Player targetPlayer = game.getPlayer(targetPointer.getFirst(game, source));

View file

@ -81,26 +81,26 @@ class KheruLichLordEffect extends OneShotEffect {
controller.moveCards(card, Zone.BATTLEFIELD, source, game);
Permanent permanent = game.getPermanent(card.getId());
if (permanent != null) {
FixedTarget fixedTarget = new FixedTarget(permanent, game);
FixedTarget blueprintTarget = new FixedTarget(permanent, game);
ContinuousEffect effect = new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn);
effect.setTargetPointer(fixedTarget);
effect.setTargetPointer(blueprintTarget.copy());
game.addEffect(effect, source);
effect = new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn);
effect.setTargetPointer(fixedTarget);
effect.setTargetPointer(blueprintTarget.copy());
game.addEffect(effect, source);
effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn);
effect.setTargetPointer(fixedTarget);
effect.setTargetPointer(blueprintTarget.copy());
game.addEffect(effect, source);
ExileTargetEffect exileEffect = new ExileTargetEffect();
exileEffect.setTargetPointer(fixedTarget);
exileEffect.setTargetPointer(blueprintTarget.copy());
DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect);
game.addDelayedTriggeredAbility(delayedAbility, source);
ReplacementEffect replacementEffect = new LeaveBattlefieldExileTargetReplacementEffect("that card");
replacementEffect.setTargetPointer(fixedTarget);
replacementEffect.setTargetPointer(blueprintTarget.copy());
game.addEffect(replacementEffect, source);
}
}

View file

@ -85,12 +85,12 @@ class KillerInstinctEffect extends OneShotEffect {
if (card.isCreature(game) && player.moveCards(card, Zone.BATTLEFIELD, source, game)) {
Permanent permanent = game.getPermanent(card.getId());
if (permanent != null) {
FixedTarget ft = new FixedTarget(permanent, game);
FixedTarget blueprintTarget = new FixedTarget(permanent, game);
ContinuousEffect effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn);
effect.setTargetPointer(ft);
effect.setTargetPointer(blueprintTarget.copy());
game.addEffect(effect, source);
Effect sacrificeEffect = new SacrificeTargetEffect("Sacrifice it at the beginning of the next end step", source.getControllerId());
sacrificeEffect.setTargetPointer(ft);
sacrificeEffect.setTargetPointer(blueprintTarget.copy());
game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect), source);
}
return true;

View file

@ -69,6 +69,7 @@ class LegionLoyalistCantBeBlockedByTokensEffect extends RestrictionEffect {
@Override
public void init(Ability source, Game game) {
super.init(source, game);
affectedObjectsSet = true;
for (Permanent perm : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_CONTROLLED_CREATURES, source.getControllerId(), source, game)) {
affectedObjectList.add(new MageObjectReference(perm, game));

View file

@ -123,6 +123,7 @@ class MournersShieldEffect extends PreventionEffectImpl {
@Override
public void init(Ability source, Game game) {
super.init(source, game);
ObjectColor colorsAmongImprinted = new ObjectColor();
Permanent sourceObject = game.getPermanent(source.getSourceId());
ExileZone exileZone = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source.getSourceId()));

View file

@ -108,9 +108,9 @@ class NacatlWarPrideEffect extends OneShotEffect {
copies.addAll(effect.getAddedPermanents());
if (!copies.isEmpty()) {
FixedTargets fixedTargets = new FixedTargets(copies, game);
FixedTargets blueprintTarget = new FixedTargets(copies, game);
ExileTargetEffect exileEffect = new ExileTargetEffect();
exileEffect.setTargetPointer(fixedTargets).setText("exile the tokens");
exileEffect.setTargetPointer(blueprintTarget.copy()).setText("exile the tokens");
game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect), source);
return true;
}

View file

@ -79,7 +79,7 @@ class NarciFableSingerEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
FixedTarget fixedTarget = targetPointer.getFixedTarget(game, source);
FixedTarget fixedTarget = targetPointer.getFirstAsFixedTarget(game, source);
if (fixedTarget == null) {
return false;
}

View file

@ -110,6 +110,8 @@ class ChangeCreatureTypeTargetEffect extends ContinuousEffectImpl {
@Override
public void init(Ability source, Game game) {
super.init(source, game);
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
return;
@ -126,8 +128,6 @@ class ChangeCreatureTypeTargetEffect extends ContinuousEffectImpl {
game.informPlayers(controller.getLogName() + " has chosen the creature type: " + fromSubType.toString());
}
}
super.init(source, game);
}
@Override

View file

@ -54,9 +54,9 @@ class NightcreepLandEffect extends BecomesBasicLandTargetEffect {
@Override
public void init(Ability source, Game game) {
super.init(source, game);
List<Permanent> targets = new ArrayList<>(game.getBattlefield().getActivePermanents(StaticFilters.FILTER_LAND, source.getControllerId(), source, game));
this.setTargetPointer(new FixedTargets(targets, game));
super.init(source, game); // must call at the end due target pointer setup
}
@Override
@ -78,9 +78,9 @@ class NightcreepCreatureEffect extends BecomesColorTargetEffect {
@Override
public void init(Ability source, Game game) {
super.init(source, game);
List<Permanent> targets = new ArrayList<>(game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source, game));
this.setTargetPointer(new FixedTargets(targets, game));
super.init(source, game); // must call at the end due target pointer setup
}
@Override

View file

@ -69,8 +69,8 @@ class NovaPentacleEffect extends RedirectionEffect {
@Override
public void init(Ability source, Game game) {
this.damageSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game);
super.init(source, game);
this.damageSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game);
}
@Override

View file

@ -89,12 +89,12 @@ class NoyanDarEffect extends OneShotEffect {
targetId = target.getFirstTarget();
}
if (targetId != null) {
FixedTarget fixedTarget = new FixedTarget(targetId, game);
FixedTarget blueprintTarget = new FixedTarget(targetId, game);
ContinuousEffect continuousEffect = new BecomesCreatureTargetEffect(new AwakenElementalToken(), false, true, Duration.EndOfGame);
continuousEffect.setTargetPointer(fixedTarget);
continuousEffect.setTargetPointer(blueprintTarget.copy());
game.addEffect(continuousEffect, source);
Effect effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance(3));
effect.setTargetPointer(fixedTarget);
effect.setTargetPointer(blueprintTarget.copy());
return effect.apply(game, source);
}
return true;

View file

@ -77,8 +77,8 @@ class OpalEyeKondasYojimboRedirectionEffect extends ReplacementEffectImpl {
@Override
public void init(Ability source, Game game) {
this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game);
super.init(source, game);
this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game);
}
@Override

View file

@ -74,6 +74,7 @@ class OraclesAttendantsReplacementEffect extends ReplacementEffectImpl {
@Override
public void init(Ability source, Game game) {
super.init(source, game);
this.targetSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game);
}

View file

@ -63,8 +63,8 @@ class PenanceEffect extends PreventionEffectImpl {
@Override
public void init(Ability source, Game game) {
this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game);
super.init(source, game);
this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game);
}
@Override

View file

@ -69,6 +69,11 @@ public final class PhantasmalTerrain extends CardImpl {
public void init(Ability source, Game game) {
super.init(source, game);
SubType choice = SubType.byDescription((String) game.getState().getValue(source.getSourceId().toString() + ChooseBasicLandTypeEffect.VALUE_KEY));
if (choice == null) {
discard();
return;
}
switch (choice) {
case FOREST:
dependencyTypes.add(DependencyType.BecomeForest);

View file

@ -82,6 +82,7 @@ class PilgrimOfJusticeEffect extends PreventionEffectImpl {
@Override
public void init(Ability source, Game game) {
super.init(source, game);
this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game);
}

View file

@ -82,6 +82,7 @@ class PilgrimOfVirtueEffect extends PreventionEffectImpl {
@Override
public void init(Ability source, Game game) {
super.init(source, game);
this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game);
}

View file

@ -97,10 +97,9 @@ class PortcullisExileEffect extends OneShotEffect {
&& controller != null) {
UUID exileZoneId = CardUtil.getExileZoneId(game, creatureToExile.getId(), creatureToExile.getZoneChangeCounter(game));
controller.moveCardsToExile(creatureToExile, source, game, true, exileZoneId, portcullis.getName());
FixedTarget fixedTarget = new FixedTarget(portcullis, game);
Effect returnEffect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, false);
returnEffect.setTargetPointer(new FixedTarget(creatureToExile.getId(), game.getState().getZoneChangeCounter(creatureToExile.getId())));
DelayedTriggeredAbility delayedAbility = new PortcullisReturnToBattlefieldTriggeredAbility(fixedTarget, returnEffect);
DelayedTriggeredAbility delayedAbility = new PortcullisReturnToBattlefieldTriggeredAbility(new FixedTarget(portcullis, game), returnEffect);
game.addDelayedTriggeredAbility(delayedAbility, source);
}
return true;
@ -109,7 +108,7 @@ class PortcullisExileEffect extends OneShotEffect {
class PortcullisReturnToBattlefieldTriggeredAbility extends DelayedTriggeredAbility {
protected FixedTarget fixedTarget;
protected final FixedTarget fixedTarget;
public PortcullisReturnToBattlefieldTriggeredAbility(FixedTarget fixedTarget, Effect effect) {
super(effect, Duration.OneUse);
@ -118,7 +117,7 @@ class PortcullisReturnToBattlefieldTriggeredAbility extends DelayedTriggeredAbil
private PortcullisReturnToBattlefieldTriggeredAbility(final PortcullisReturnToBattlefieldTriggeredAbility ability) {
super(ability);
this.fixedTarget = ability.fixedTarget;
this.fixedTarget = ability.fixedTarget.copy();
}
@Override

View file

@ -58,9 +58,9 @@ class PrismaticCircleEffect extends PreventNextDamageFromChosenSourceToYouEffect
@Override
public void init(Ability source, Game game) {
super.init(source, game);
FilterObject filter = targetSource.getFilter();
filter.add(new ColorPredicate((ObjectColor) game.getState().getValue(source.getSourceId() + "_color")));
super.init(source, game);
}
private PrismaticCircleEffect(final PrismaticCircleEffect effect) {

View file

@ -64,6 +64,7 @@ class ProgenitorsIconAsThoughEffect extends AsThoughEffectImpl {
@Override
public void init(Ability source, Game game) {
super.init(source, game);
SubType subType = ChooseCreatureTypeEffect.getChosenCreatureType(source.getSourceId(), game);
ProgenitorsIconWatcher.addPlayer(source.getControllerId(), subType, game);
}

View file

@ -75,6 +75,7 @@ class ProtectiveSphereEffect extends PreventionEffectImpl {
@Override
public void init(Ability source, Game game) {
super.init(source, game);
target.withNotTarget(true);
target.setRequired(false);
Player controller = game.getPlayer(source.getControllerId());
@ -89,7 +90,6 @@ class ProtectiveSphereEffect extends PreventionEffectImpl {
+ source.getManaCostsToPay().getUsedManaToPay()), game);
}
this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game);
super.init(source, game);
}
@Override

View file

@ -109,14 +109,14 @@ class PullEffect extends OneShotEffect {
}
permanents.forEach(permanent -> {
FixedTarget target = new FixedTarget(permanent, game);
FixedTarget blueprintTarget = new FixedTarget(permanent, game);
ContinuousEffect effect = new GainAbilityTargetEffect(HasteAbility.getInstance());
effect.setTargetPointer(target);
effect.setTargetPointer(blueprintTarget.copy());
game.addEffect(effect, source);
Effect sacrificeEffect = new SacrificeTargetEffect("sacrifice " + permanent.getLogName(), controller.getId());
sacrificeEffect.setTargetPointer(target);
sacrificeEffect.setTargetPointer(blueprintTarget.copy());
game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect), source);
});

View file

@ -64,6 +64,7 @@ class QuickenAsThoughEffect extends AsThoughEffectImpl {
@Override
public void init(Ability source, Game game) {
super.init(source, game);
quickenWatcher = game.getState().getWatcher(QuickenWatcher.class);
Card card = game.getCard(source.getSourceId());
if (quickenWatcher != null && card != null) {

View file

@ -66,6 +66,11 @@ class RealmwrightEffect extends ContinuousEffectImpl {
public void init(Ability source, Game game) {
super.init(source, game);
SubType choice = SubType.byDescription((String) game.getState().getValue(source.getSourceId().toString() + ChooseBasicLandTypeEffect.VALUE_KEY));
if (choice == null) {
discard();
return;
}
switch (choice) {
case PLAINS:
dependencyTypes.add(DependencyType.BecomePlains);

View file

@ -106,8 +106,8 @@ class RefractionTrapPreventDamageEffect extends PreventionEffectImpl {
@Override
public void init(Ability source, Game game) {
this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game);
super.init(source, game);
this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game);
}
@Override

View file

@ -61,6 +61,7 @@ class ReverseDamageEffect extends PreventionEffectImpl {
@Override
public void init(Ability source, Game game) {
super.init(source, game);
this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game);
}

View file

@ -57,6 +57,7 @@ class RideTheAvalancheAsThoughEffect extends AsThoughEffectImpl {
@Override
public void init(Ability source, Game game) {
super.init(source, game);
RideTheAvalancheWatcher.addPlayer(source.getControllerId(), game);
}

View file

@ -120,6 +120,7 @@ class RuneswordCantBeRegeneratedEffect extends ContinuousRuleModifyingEffectImpl
}
public void init(Ability source, Game game) {
super.init(source, game);
targetCreatureId = getTargetPointer().getFirst(game, source);
}

View file

@ -62,6 +62,7 @@ class SamiteMinistrationEffect extends PreventionEffectImpl {
@Override
public void init(Ability source, Game game) {
super.init(source, game);
this.targetSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game);
}

View file

@ -72,6 +72,7 @@ class SavageSummoningAsThoughEffect extends AsThoughEffectImpl {
@Override
public void init(Ability source, Game game) {
super.init(source, game);
watcher = game.getState().getWatcher(SavageSummoningWatcher.class, source.getControllerId());
Card card = game.getCard(source.getSourceId());
if (watcher != null && card != null) {
@ -188,6 +189,7 @@ class SavageSummoningCantCounterEffect extends ContinuousRuleModifyingEffectImpl
@Override
public void init(Ability source, Game game) {
super.init(source, game);
watcher = game.getState().getWatcher(SavageSummoningWatcher.class, source.getControllerId());
Card card = game.getCard(source.getSourceId());
if (watcher == null || card == null) {
@ -244,6 +246,7 @@ class SavageSummoningEntersBattlefieldEffect extends ReplacementEffectImpl {
@Override
public void init(Ability source, Game game) {
super.init(source, game);
watcher = game.getState().getWatcher(SavageSummoningWatcher.class, source.getControllerId());
Card card = game.getCard(source.getSourceId());
if (watcher == null || card == null) {

View file

@ -95,7 +95,6 @@ class ScholarOfTheLostTroveEffect extends OneShotEffect {
if (!controller.chooseUse(Outcome.PlayForFree, "Cast " + card.getLogName() + '?', source, game)) {
return true;
}
FixedTarget fixedTarget = new FixedTarget(card, game);
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true),
game, true, new ApprovingObject(source, game));
@ -104,7 +103,7 @@ class ScholarOfTheLostTroveEffect extends OneShotEffect {
return true;
}
ContinuousEffect effect = new ThatSpellGraveyardExileReplacementEffect(true);
effect.setTargetPointer(fixedTarget);
effect.setTargetPointer(new FixedTarget(card, game));
effect.setText("If an instant or sorcery spell cast this way would be put into your graveyard this turn, exile it instead");
game.addEffect(effect, source);
return true;

View file

@ -63,6 +63,7 @@ class ScoutsWarningAsThoughEffect extends AsThoughEffectImpl {
@Override
public void init(Ability source, Game game) {
super.init(source, game);
ScoutsWarningWatcher watcher = game.getState().getWatcher(ScoutsWarningWatcher.class, source.getControllerId());
Card card = game.getCard(source.getSourceId());
if (watcher != null && card != null) {

View file

@ -76,14 +76,14 @@ class ShallowGraveEffect extends OneShotEffect {
if (controller.moveCards(lastCreatureCard, Zone.BATTLEFIELD, source, game)) {
Permanent returnedCreature = game.getPermanent(lastCreatureCard.getId());
if (returnedCreature != null) {
FixedTarget fixedTarget = new FixedTarget(returnedCreature, game);
FixedTarget blueprintTarget = new FixedTarget(returnedCreature, game);
// Gains Haste
ContinuousEffect hasteEffect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn);
hasteEffect.setTargetPointer(fixedTarget);
hasteEffect.setTargetPointer(blueprintTarget.copy());
game.addEffect(hasteEffect, source);
// Exile it at end of turn
ExileTargetEffect exileEffect = new ExileTargetEffect(null, "", Zone.BATTLEFIELD);
exileEffect.setTargetPointer(fixedTarget);
exileEffect.setTargetPointer(blueprintTarget.copy());
DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect);
game.addDelayedTriggeredAbility(delayedAbility, source);
}

View file

@ -83,6 +83,7 @@ class ShamanEnKorRedirectFromTargetEffect extends RedirectionEffect {
@Override
public void init(Ability source, Game game) {
super.init(source, game);
Player player = game.getPlayer(source.getControllerId());
if (player != null) {
TargetSource target = new TargetSource();

View file

@ -82,6 +82,7 @@ class ShieldmageAdvocateEffect extends PreventionEffectImpl {
@Override
public void init(Ability source, Game game) {
super.init(source, game);
this.targetSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game);
}

View file

@ -86,6 +86,7 @@ class ShiningShoalRedirectDamageTargetEffect extends RedirectDamageFromSourceToT
@Override
public void init(Ability source, Game game) {
super.init(source, game);
amountToRedirect = dynamicAmount.calculate(game, source, this);
}

View file

@ -90,14 +90,14 @@ class ShowOfDominanceEffect extends OneShotEffect {
}
}
if (selectedCreature != null) {
FixedTarget target = new FixedTarget(selectedCreature.getId(), game);
FixedTarget blueprintTarget = new FixedTarget(selectedCreature.getId(), game);
Effect effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance(4));
effect.setTargetPointer(target);
effect.setTargetPointer(blueprintTarget.copy());
effect.apply(game, source);
ContinuousEffect continuousEffect = new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn);
continuousEffect.setTargetPointer(target);
continuousEffect.setTargetPointer(blueprintTarget.copy());
game.addEffect(continuousEffect, source);
return true;
}

View file

@ -54,9 +54,9 @@ class StoryCircleEffect extends PreventNextDamageFromChosenSourceToYouEffect {
@Override
public void init(Ability source, Game game) {
super.init(source, game);
FilterObject filter = targetSource.getFilter();
filter.add(new ColorPredicate((ObjectColor) game.getState().getValue(source.getSourceId() + "_color")));
super.init(source, game);
}
private StoryCircleEffect(final StoryCircleEffect effect) {

View file

@ -110,7 +110,7 @@ class TadeasJuniperAscendantEvasionEffect extends RestrictionEffect {
TadeasJuniperAscendantEvasionEffect(TargetPointer targetPointer) {
super(Duration.EndOfCombat);
this.targetPointer = targetPointer;
this.setTargetPointer(targetPointer);
staticText = "and can't be blocked by creatures with greater power";
}

View file

@ -83,6 +83,7 @@ class TenthDistrictHeroEffect extends ContinuousEffectImpl {
@Override
public void init(Ability source, Game game) {
super.init(source, game);
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
if (permanent == null || !permanent.hasSubtype(SubType.DETECTIVE, game)) {
discard();

View file

@ -98,6 +98,11 @@ class TerraformerContinuousEffect extends ContinuousEffectImpl {
public void init(Ability source, Game game) {
super.init(source, game);
SubType choice = SubType.byDescription((String) game.getState().getValue(source.getSourceId().toString() + "_Terraformer"));
if (choice == null) {
discard();
return;
}
switch (choice) {
case FOREST:
dependencyTypes.add(DependencyType.BecomeForest);

View file

@ -97,7 +97,7 @@ class TezzeretCruelMachinistEffect extends OneShotEffect {
.getCards(game)
.stream()
.map(card -> new MageObjectReference(card, game, 1))
.collect(Collectors.toSet()), game
.collect(Collectors.toList())
)), source);
player.moveCards(
cardsToMove.getCards(game), Zone.BATTLEFIELD, source, game,

View file

@ -248,8 +248,8 @@ class AddCardSubTypeEnteringTargetEffect extends ContinuousEffectImpl {
@Override
public boolean apply(Game game, Ability source) {
Spell spell = game.getSpell(targetPointer.getFixedTarget(game, source).getTarget());
MageObject target = game.getObject(targetPointer.getFixedTarget(game, source).getTarget());
Spell spell = game.getSpell(targetPointer.getFirst(game, source));
MageObject target = game.getObject(targetPointer.getFirst(game, source));
if (spell != null) {
card = spell.getCard();
}

View file

@ -94,6 +94,11 @@ class ThranPortalManaAbilityContinousEffect extends ContinuousEffectImpl {
public void init(Ability source, Game game) {
super.init(source, game);
SubType choice = SubType.byDescription((String) game.getState().getValue(source.getSourceId().toString() + ChooseBasicLandTypeEffect.VALUE_KEY));
if (choice == null) {
discard();
return;
}
switch (choice) {
case FOREST:
dependencyTypes.add(DependencyType.BecomeForest);

View file

@ -92,11 +92,10 @@ class TideShaperEffect extends BecomesBasicLandTargetEffect {
@Override
public void init(Ability source, Game game) {
super.init(source, game);
if (source.getSourcePermanentIfItStillExists(game) == null) {
discard();
return;
}
super.init(source, game);
}
@Override

View file

@ -89,8 +89,6 @@ class TreasureNabberAbility extends TriggeredAbilityImpl {
class TreasureNabberEffect extends ContinuousEffectImpl {
protected FixedTargets fixedTargets;
TreasureNabberEffect() {
super(Duration.UntilEndOfYourNextTurn, Layer.ControlChangingEffects_2, SubLayer.NA, Outcome.GainControl);
this.staticText = "gain control of that artifact until the end of your next turn";
@ -98,7 +96,6 @@ class TreasureNabberEffect extends ContinuousEffectImpl {
private TreasureNabberEffect(final TreasureNabberEffect effect) {
super(effect);
this.fixedTargets = effect.fixedTargets;
}
@Override
@ -116,8 +113,4 @@ class TreasureNabberEffect extends ContinuousEffectImpl {
}
return false;
}
public void setTargets(List<Permanent> targetedPermanents, Game game) {
this.fixedTargets = new FixedTargets(targetedPermanents, game);
}
}

View file

@ -106,13 +106,13 @@ class WakeToSlaughterEffect extends OneShotEffect {
} else {
player.moveCards(card, Zone.BATTLEFIELD, source, game);
FixedTarget fixedTarget = new FixedTarget(card, game);
FixedTarget blueprintTarget = new FixedTarget(card, game);
ContinuousEffect effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfGame);
effect.setTargetPointer(fixedTarget);
effect.setTargetPointer(blueprintTarget.copy());
game.addEffect(effect, source);
ExileTargetEffect exileEffect = new ExileTargetEffect(null, null, Zone.BATTLEFIELD);
exileEffect.setTargetPointer(fixedTarget);
exileEffect.setTargetPointer(blueprintTarget.copy());
DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect);
game.addDelayedTriggeredAbility(delayedAbility, source);
}

View file

@ -61,6 +61,7 @@ class WelcomeToTheFoldEffect extends GainControlTargetEffect {
@Override
public void init(Ability source, Game game) {
super.init(source, game);
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
int maxToughness = 2;
@ -71,10 +72,8 @@ class WelcomeToTheFoldEffect extends GainControlTargetEffect {
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (permanent != null && permanent.getToughness().getValue() > maxToughness) {
this.discard();
return;
}
}
super.init(source, game);
}
@Override

View file

@ -11,6 +11,7 @@ import mage.game.permanent.Permanent;
import mage.target.targetpointer.FixedTargets;
import mage.util.CardUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
@ -91,7 +92,7 @@ public class AttacksWithCreaturesTriggeredAbility extends TriggeredAbilityImpl {
}
getEffects().setValue(VALUEKEY_NUMBER_ATTACKERS, attackers.size());
if (setTargetPointer) {
getEffects().setTargetPointer(new FixedTargets(attackers, game));
getEffects().setTargetPointer(new FixedTargets(new ArrayList<>(attackers), game));
}
return true;
}

View file

@ -18,6 +18,7 @@ import mage.util.CardUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* @author nantuko
@ -95,7 +96,7 @@ public class ExileFromGraveCost extends CostImpl {
CardUtil.getSourceName(game, source)
);
if (setTargetPointer) {
source.getEffects().setTargetPointer(new FixedTargets(cardsToExile, game));
source.getEffects().setTargetPointer(new FixedTargets(cardsToExile.getCards(game), game));
}
paid = true;
}

View file

@ -39,6 +39,11 @@ public interface ContinuousEffect extends Effect {
boolean isInactive(Ability source, Game game);
/**
* Init ability data like ZCC or targets on first check in game cycle (ApplyEffects)
* <p>
* Warning, if you setup target pointer in init then must call super.init at the end (after all choices)
*/
void init(Ability source, Game game);
void init(Ability source, Game game, UUID activePlayerId);

View file

@ -3,7 +3,6 @@ package mage.abilities.effects;
import mage.MageObjectReference;
import mage.abilities.Ability;
import mage.abilities.CompoundAbility;
import mage.abilities.MageSingleton;
import mage.abilities.keyword.ChangelingAbility;
import mage.constants.*;
import mage.filter.Filter;
@ -154,6 +153,11 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu
this.discarded = true;
}
@Override
public final void initNewTargetPointer() {
// continuous effect uses init code, so do nothing here
}
@Override
public void init(Ability source, Game game) {
init(source, game, game.getActivePlayerId());

View file

@ -21,6 +21,8 @@ public abstract class EffectImpl implements Effect {
protected EffectType effectType;
// read related docs about static and dynamic targets in ContinuousEffectImpl.affectedObjectsSet
// warning, do not change it directly, use setTargetPointer instead
// TODO: make it private and replace all usage to getTargetPointer
protected TargetPointer targetPointer = new FirstTargetPointer();
protected String staticText = "";
@ -30,6 +32,8 @@ public abstract class EffectImpl implements Effect {
public EffectImpl(Outcome outcome) {
this.id = UUID.randomUUID();
this.outcome = outcome;
initNewTargetPointer();
}
protected EffectImpl(final EffectImpl effect) {
@ -48,6 +52,11 @@ public abstract class EffectImpl implements Effect {
}
}
/**
* Init target pointer by default (see TargetPointer for details)
*/
abstract public void initNewTargetPointer();
@Override
public UUID getId() {
return id;
@ -81,7 +90,13 @@ public abstract class EffectImpl implements Effect {
@Override
public Effect setTargetPointer(TargetPointer targetPointer) {
if (targetPointer == null) {
// first target pointer is default
throw new IllegalArgumentException("Wrong code usage: target pointer can't be set to null: " + this);
}
this.targetPointer = targetPointer;
initNewTargetPointer();
return this;
}

View file

@ -4,6 +4,7 @@ package mage.abilities.effects;
import mage.constants.EffectType;
import mage.constants.Outcome;
import mage.target.targetpointer.TargetPointer;
/**
* @author BetaSteward_at_googlemail.com
@ -15,6 +16,12 @@ public abstract class OneShotEffect extends EffectImpl {
this.effectType = EffectType.ONESHOT;
}
@Override
public final void initNewTargetPointer() {
// one short effects don't use init logic
this.targetPointer.setInitialized();
}
protected OneShotEffect(final OneShotEffect effect) {
super(effect);
}
@ -24,4 +31,10 @@ public abstract class OneShotEffect extends EffectImpl {
super.setText(staticText);
return this;
}
@Override
public Effect setTargetPointer(TargetPointer targetPointer) {
super.setTargetPointer(targetPointer);
return this;
}
}

View file

@ -25,6 +25,7 @@ import mage.util.functions.CopyTokenFunction;
import mage.util.functions.EmptyCopyApplier;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author LevelX2
@ -418,7 +419,7 @@ public class CreateTokenCopyTargetEffect extends OneShotEffect {
} else {
effect = new SacrificeTargetEffect("sacrifice the token copies", source.getControllerId());
}
effect.setTargetPointer(new FixedTargets(addedTokenPermanents, game));
effect.setTargetPointer(new FixedTargets(new ArrayList<>(addedTokenPermanents), game));
DelayedTriggeredAbility exileAbility;

View file

@ -46,8 +46,7 @@ public class DetainAllEffect extends OneShotEffect {
if (!game.isSimulation()) {
game.informPlayers("Detained permanent: " + permanent.getName());
}
FixedTarget fixedTarget = new FixedTarget(permanent, game);
detainedObjects.add(fixedTarget);
detainedObjects.add(new FixedTarget(permanent, game));
}
game.addEffect(new DetainAllRestrictionEffect(detainedObjects), source);

View file

@ -13,6 +13,7 @@ import mage.players.Player;
import mage.target.targetpointer.FixedTargets;
import mage.util.CardUtil;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.Objects;
import java.util.Set;
@ -74,7 +75,7 @@ public class ExileReturnBattlefieldNextEndStepTargetEffect extends OneShotEffect
Effect effect = yourControl
? new ReturnToBattlefieldUnderYourControlTargetEffect(exiledOnly)
: new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, exiledOnly);
effect.setTargetPointer(new FixedTargets(new CardsImpl(toExile), game));
effect.setTargetPointer(new FixedTargets(toExile, game));
game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect), source);
return true;
}

View file

@ -1,5 +1,6 @@
package mage.abilities.effects.common;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.StaticValue;
@ -14,7 +15,9 @@ import mage.players.Player;
import mage.target.targetpointer.FixedTargets;
import mage.util.CardUtil;
import java.util.ArrayList;
import java.util.Set;
import java.util.stream.Collectors;
public class ExileTopXMayPlayUntilEffect extends OneShotEffect {

View file

@ -42,6 +42,7 @@ public class PreventAllDamageFromChosenSourceToYouEffect extends PreventionEffec
@Override
public void init(Ability source, Game game) {
super.init(source, game);
this.targetSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game);
// be sure to note the target source's zcc, etc, if able.
if (targetSource.getFirstTarget() != null) {

View file

@ -47,6 +47,7 @@ public class PreventDamageBySourceEffect extends PreventionEffectImpl {
@Override
public void init(Ability source, Game game) {
super.init(source, game);
this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game);
mageObjectReference = new MageObjectReference(target.getFirstTarget(), game);
}

View file

@ -43,6 +43,7 @@ public class PreventNextDamageFromChosenSourceToTargetEffect extends PreventionE
@Override
public void init(Ability source, Game game) {
super.init(source, game);
this.targetSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game);
}

View file

@ -43,6 +43,7 @@ public class PreventNextDamageFromChosenSourceToYouEffect extends PreventionEffe
@Override
public void init(Ability source, Game game) {
super.init(source, game);
this.targetSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game);
}

View file

@ -27,7 +27,7 @@ public class ReturnToHandChosenControlledPermanentEffect extends ReturnToHandCho
@Override
public boolean apply(Game game, Ability source) {
this.targetPointer = new FixedTarget(source.getControllerId());
this.setTargetPointer(new FixedTarget(source.getControllerId()));
return super.apply(game, source);
}

View file

@ -31,7 +31,7 @@ public class SacrificeControllerEffect extends SacrificeEffect {
@Override
public boolean apply(Game game, Ability source) {
this.targetPointer = new FixedTarget(source.getControllerId());
this.setTargetPointer(new FixedTarget(source.getControllerId()));
return super.apply(game, source);
}

View file

@ -13,10 +13,7 @@ import mage.target.targetpointer.FixedTarget;
import mage.target.targetpointer.FixedTargets;
import mage.util.CardUtil;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.*;
import java.util.stream.Collectors;
/**

View file

@ -71,8 +71,11 @@ public class BecomesColorSourceEffect extends ContinuousEffectImpl {
@Override
public void init(Ability source, Game game) {
super.init(source, game);
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
discard();
return;
}
if (setColor == null) {
@ -86,7 +89,6 @@ public class BecomesColorSourceEffect extends ContinuousEffectImpl {
game.informPlayers(controller.getLogName() + " has chosen the color: " + setColor.toString());
}
}
super.init(source, game);
}
@Override

View file

@ -50,8 +50,11 @@ public class BecomesColorTargetEffect extends ContinuousEffectImpl {
@Override
public void init(Ability source, Game game) {
super.init(source, game);
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
discard();
return;
}
if (setColor == null) {
@ -65,8 +68,6 @@ public class BecomesColorTargetEffect extends ContinuousEffectImpl {
game.informPlayers(controller.getLogName() + " has chosen the color: " + setColor.toString());
}
}
super.init(source, game);
}
@Override

Some files were not shown because too many files have changed in this diff Show more