Tibalt, Cosmic Impostor - fixed that emblem can't cast not owned cards (#7598)

* Fixed ability.canChooseTarget not using correct playerId

* Fixed Necrotic Plague

* Revert "Fixed Necrotic Plague"

This reverts commit 7659039670.

* Set target controller on Necrotic Plague and add check in canChooseTarget

* Add test for Tibalt + Ephemerate interaction

* Tests improved

Co-authored-by: Oleg Agafonov <jaydi85@gmail.com>
This commit is contained in:
Daniel Bomar 2021-02-22 13:06:43 -06:00 committed by GitHub
parent b94af941df
commit bb0a995541
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 84 additions and 31 deletions

View file

@ -320,7 +320,7 @@ public interface Ability extends Controllable, Serializable {
Modes getModes();
boolean canChooseTarget(Game game);
boolean canChooseTarget(Game game, UUID playerId);
/**
* Gets the list of sub-abilities associated with this ability.

View file

@ -901,24 +901,36 @@ public abstract class AbilityImpl implements Ability {
}
@Override
public boolean canChooseTarget(Game game) {
public boolean canChooseTarget(Game game, UUID playerId) {
if (this instanceof SpellAbility) {
if (SpellAbilityType.SPLIT_FUSED.equals(((SpellAbility) this).getSpellAbilityType())) {
Card card = game.getCard(getSourceId());
if (card != null) {
return canChooseTargetAbility(((SplitCard) card).getLeftHalfCard().getSpellAbility(), game, getControllerId())
&& canChooseTargetAbility(((SplitCard) card).getRightHalfCard().getSpellAbility(), game, getControllerId());
return canChooseTargetAbility(((SplitCard) card).getLeftHalfCard().getSpellAbility(), game, playerId)
&& canChooseTargetAbility(((SplitCard) card).getRightHalfCard().getSpellAbility(), game, playerId);
}
return false;
}
}
return canChooseTargetAbility(this, game, getControllerId());
return canChooseTargetAbility(this, game, playerId);
}
private static boolean canChooseTargetAbility(Ability ability, Game game, UUID controllerId) {
int found = 0;
for (Mode mode : ability.getModes().values()) {
if (mode.getTargets().canChoose(ability.getSourceId(), ability.getControllerId(), game)) {
boolean validTargets = true;
for (Target target : mode.getTargets()) {
UUID abilityControllerId = controllerId;
if (target.getTargetController() != null) {
abilityControllerId = target.getTargetController();
}
if (!target.canChoose(ability.getSourceId(), abilityControllerId, game)) {
validTargets = false;
break;
}
}
if (validTargets) {
found++;
if (ability.getModes().isEachModeMoreThanOnce()) {
return true;

View file

@ -194,7 +194,7 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa
|| game.canPlaySorcery(playerId)
|| null != approvingObject) {
if (costs.canPay(this, this, playerId, game)
&& canChooseTarget(game)) {
&& canChooseTarget(game, playerId)) {
this.activatorId = playerId;
return new ActivationStatus(true, approvingObject);
}

View file

@ -118,13 +118,13 @@ public class SpellAbility extends ActivatedAbilityImpl {
// fused can be called from hand only, so not permitting object allows or other zones checks
// see https://www.mtgsalvation.com/forums/magic-fundamentals/magic-rulings/magic-rulings-archives/251926-snapcaster-mage-and-fuse
if (game.getState().getZone(splitCard.getId()) == Zone.HAND) {
return new ActivationStatus(splitCard.getLeftHalfCard().getSpellAbility().canChooseTarget(game)
&& splitCard.getRightHalfCard().getSpellAbility().canChooseTarget(game), null);
return new ActivationStatus(splitCard.getLeftHalfCard().getSpellAbility().canChooseTarget(game, playerId)
&& splitCard.getRightHalfCard().getSpellAbility().canChooseTarget(game, playerId), null);
}
}
return ActivationStatus.getFalse();
} else {
return new ActivationStatus(canChooseTarget(game), approvingObject);
return new ActivationStatus(canChooseTarget(game, playerId), approvingObject);
}
}
}

View file

@ -76,7 +76,7 @@ public class CastWithoutPayingManaCostEffect extends OneShotEffect {
+ cardToCast.getName() + " is no land and has no spell ability!");
cancel = true;
}
if (cardToCast.getSpellAbility().canChooseTarget(game)) {
if (cardToCast.getSpellAbility().canChooseTarget(game, controller.getId())) {
cancel = true;
}
}

View file

@ -437,8 +437,8 @@ public class StackAbility extends StackObjImpl implements Ability {
}
@Override
public boolean canChooseTarget(Game game) {
return ability.canChooseTarget(game);
public boolean canChooseTarget(Game game, UUID playerId) {
return ability.canChooseTarget(game, playerId);
}
@Override

View file

@ -1495,7 +1495,7 @@ public abstract class PlayerImpl implements Player, Serializable {
if (sourceObject != null) {
sourceObject.adjustTargets(ability, game);
}
if (ability.canChooseTarget(game)) {
if (ability.canChooseTarget(game, playerId)) {
if (ability.isUsesStack()) {
game.getStack().push(new StackAbility(ability, playerId));
}
@ -1539,28 +1539,28 @@ public abstract class PlayerImpl implements Player, Serializable {
return useable;
case SPLIT_FUSED:
if (zone == Zone.HAND) {
if (ability.canChooseTarget(game)) {
if (ability.canChooseTarget(game, playerId)) {
useable.put(ability.getId(), (SpellAbility) ability);
}
}
case SPLIT:
if (((SplitCard) object).getLeftHalfCard().getSpellAbility().canChooseTarget(game)) {
if (((SplitCard) object).getLeftHalfCard().getSpellAbility().canChooseTarget(game, playerId)) {
useable.put(((SplitCard) object).getLeftHalfCard().getSpellAbility().getId(),
((SplitCard) object).getLeftHalfCard().getSpellAbility());
}
if (((SplitCard) object).getRightHalfCard().getSpellAbility().canChooseTarget(game)) {
if (((SplitCard) object).getRightHalfCard().getSpellAbility().canChooseTarget(game, playerId)) {
useable.put(((SplitCard) object).getRightHalfCard().getSpellAbility().getId(),
((SplitCard) object).getRightHalfCard().getSpellAbility());
}
return useable;
case SPLIT_AFTERMATH:
if (zone == Zone.GRAVEYARD) {
if (((SplitCard) object).getRightHalfCard().getSpellAbility().canChooseTarget(game)) {
if (((SplitCard) object).getRightHalfCard().getSpellAbility().canChooseTarget(game, playerId)) {
useable.put(((SplitCard) object).getRightHalfCard().getSpellAbility().getId(),
((SplitCard) object).getRightHalfCard().getSpellAbility());
}
} else {
if (((SplitCard) object).getLeftHalfCard().getSpellAbility().canChooseTarget(game)) {
if (((SplitCard) object).getLeftHalfCard().getSpellAbility().canChooseTarget(game, playerId)) {
useable.put(((SplitCard) object).getLeftHalfCard().getSpellAbility().getId(),
((SplitCard) object).getLeftHalfCard().getSpellAbility());
}

View file

@ -4,10 +4,10 @@ import mage.abilities.Ability;
import mage.game.Game;
/**
*
* @author TheElk801
*/
public interface TargetAdjuster {
void adjustTargets(Ability ability, Game game);
}