mirror of
https://github.com/magefree/mage.git
synced 2026-01-26 21:29:17 -08:00
More target adding, reattach improves (#13807)
* Add Target to Provoke, Soulshift, remove from AttachableToRestrictedAbility * Add Target to CurseOfInertia, FarrelsMantle, Incendiary, JubilantMascot, MantleOfTheAncients, MuseVessel, SoulSeizer. Fix DreamEater text. * Fix CardImpl.cantBeAttachedBy to not early return with Protection abilities * Improve tests
This commit is contained in:
parent
8fda57401d
commit
7d7e517084
17 changed files with 273 additions and 260 deletions
|
|
@ -4,35 +4,30 @@ import mage.abilities.Ability;
|
|||
import mage.abilities.effects.common.InfoEffect;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.target.Target;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class AttachableToRestrictedAbility extends SimpleStaticAbility {
|
||||
|
||||
private final Target attachable;
|
||||
public AttachableToRestrictedAbility(Target target) {
|
||||
super(Zone.BATTLEFIELD, new InfoEffect("{this} can be attached only to a " + target.getTargetName()));
|
||||
addTarget(target);
|
||||
this.attachable = target.copy();
|
||||
}
|
||||
|
||||
private AttachableToRestrictedAbility(AttachableToRestrictedAbility ability) {
|
||||
super(ability);
|
||||
this.attachable = ability.attachable; // Since we never modify the target, we don't need to re-copy it
|
||||
}
|
||||
|
||||
public boolean canEquip(Permanent toEquip, Ability source, Game game) {
|
||||
for (Target target : getTargets()) {
|
||||
if (source == null) {
|
||||
if (!target.canTarget(toEquip.getId(), game)) {
|
||||
return false;
|
||||
}
|
||||
} else if (!target.canTarget(toEquip.getId(), source, game)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
public boolean canEquip(UUID toEquip, Ability source, Game game) {
|
||||
if (source == null) {
|
||||
return attachable.canTarget(toEquip, game);
|
||||
} else return attachable.canTarget(toEquip, source, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -6,12 +6,12 @@ import mage.abilities.common.AttacksTriggeredAbility;
|
|||
import mage.abilities.effects.RequirementEffect;
|
||||
import mage.abilities.effects.common.UntapTargetEffect;
|
||||
import mage.constants.Duration;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.filter.predicate.permanent.ControllerIdPredicate;
|
||||
import mage.constants.SetTargetPointer;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.target.TargetPermanent;
|
||||
import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
|
|
@ -31,27 +31,16 @@ public class ProvokeAbility extends AttacksTriggeredAbility {
|
|||
}
|
||||
|
||||
public ProvokeAbility(String text) {
|
||||
super(new UntapTargetEffect(), true, text);
|
||||
super(new UntapTargetEffect(), true, text, SetTargetPointer.PLAYER);
|
||||
this.addEffect(new ProvokeRequirementEffect());
|
||||
this.addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_CREATURE));
|
||||
this.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
|
||||
}
|
||||
|
||||
protected ProvokeAbility(final ProvokeAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (super.checkTrigger(event, game)) {
|
||||
FilterCreaturePermanent filter = new FilterCreaturePermanent("creature defending player controls");
|
||||
UUID defendingPlayerId = game.getCombat().getDefendingPlayerId(sourceId, game);
|
||||
filter.add(new ControllerIdPredicate(defendingPlayerId));
|
||||
this.getTargets().clear();
|
||||
this.addTarget(new TargetPermanent(filter));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProvokeAbility copy() {
|
||||
return new ProvokeAbility(this);
|
||||
|
|
|
|||
|
|
@ -2,19 +2,15 @@
|
|||
|
||||
package mage.abilities.keyword;
|
||||
|
||||
import mage.constants.ComparisonType;
|
||||
import mage.abilities.common.DiesSourceTriggeredAbility;
|
||||
import mage.abilities.dynamicvalue.DynamicValue;
|
||||
import mage.abilities.dynamicvalue.common.StaticValue;
|
||||
import mage.abilities.effects.common.ReturnToHandTargetEffect;
|
||||
import mage.constants.ComparisonType;
|
||||
import mage.constants.SubType;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.predicate.mageobject.ManaValuePredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.target.common.TargetCardInYourGraveyard;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.target.targetadjustment.ManaValueTargetAdjuster;
|
||||
|
||||
/**
|
||||
* 702.45. Soulshift
|
||||
|
|
@ -38,6 +34,10 @@ public class SoulshiftAbility extends DiesSourceTriggeredAbility {
|
|||
public SoulshiftAbility(DynamicValue amount) {
|
||||
super(new ReturnToHandTargetEffect());
|
||||
this.amount = amount;
|
||||
FilterCard filter = new FilterCard("Spirit card from your graveyard");
|
||||
filter.add(SubType.SPIRIT.getPredicate());
|
||||
this.addTarget(new TargetCardInYourGraveyard(filter));
|
||||
this.setTargetAdjuster(new ManaValueTargetAdjuster(amount, ComparisonType.OR_LESS));
|
||||
}
|
||||
|
||||
protected SoulshiftAbility(final SoulshiftAbility ability) {
|
||||
|
|
@ -45,17 +45,6 @@ public class SoulshiftAbility extends DiesSourceTriggeredAbility {
|
|||
this.amount = ability.amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trigger(Game game, UUID controllerId, GameEvent triggeringEvent) {
|
||||
this.getTargets().clear();
|
||||
int intValue = amount.calculate(game, this, null);
|
||||
FilterCard filter = new FilterCard("Spirit card with mana value " + intValue + " or less from your graveyard");
|
||||
filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, intValue + 1));
|
||||
filter.add(SubType.SPIRIT.getPredicate());
|
||||
this.addTarget(new TargetCardInYourGraveyard(filter));
|
||||
super.trigger(game, controllerId, triggeringEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoulshiftAbility copy() {
|
||||
return new SoulshiftAbility(this);
|
||||
|
|
|
|||
|
|
@ -918,27 +918,41 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
|||
|
||||
@Override
|
||||
public boolean cantBeAttachedBy(MageObject attachment, Ability source, Game game, boolean silentMode) {
|
||||
boolean canAttach = true;
|
||||
for (ProtectionAbility ability : this.getAbilities(game).getProtectionAbilities()) {
|
||||
if ((!attachment.hasSubtype(SubType.AURA, game) || ability.removesAuras())
|
||||
&& (!attachment.hasSubtype(SubType.EQUIPMENT, game) || ability.removesEquipment())
|
||||
&& !attachment.getId().equals(ability.getAuraIdNotToBeRemoved())
|
||||
&& !ability.canTarget(attachment, game)) {
|
||||
return !ability.getDoesntRemoveControlled() || Objects.equals(getControllerOrOwnerId(), game.getControllerId(attachment.getId()));
|
||||
canAttach &= ability.getDoesntRemoveControlled() && Objects.equals(getControllerOrOwnerId(), game.getControllerId(attachment.getId()));
|
||||
}
|
||||
}
|
||||
|
||||
boolean canAttach = true;
|
||||
Permanent attachmentPermanent = game.getPermanent(attachment.getId());
|
||||
// If attachment is an aura, ensures this permanent can still be legally enchanted, according to the enchantment's Enchant ability
|
||||
if (attachment.hasSubtype(SubType.AURA, game)
|
||||
&& attachmentPermanent != null
|
||||
&& attachmentPermanent.getSpellAbility() != null
|
||||
&& !attachmentPermanent.getSpellAbility().getTargets().isEmpty()) {
|
||||
// Line of code below functionally gets the target of the aura's Enchant ability, then compares to this permanent. Enchant improperly implemented in XMage, see #9583
|
||||
// Note: stillLegalTarget used exclusively to account for Dream Leash. Can be made canTarget in the event that that card is rewritten (and "stillLegalTarget" removed from TargetImpl).
|
||||
canAttach = attachmentPermanent.getSpellAbility().getTargets().get(0).copy().withNotTarget(true).stillLegalTarget(attachmentPermanent.getControllerId(), this.getId(), source, game);
|
||||
if (attachment.hasSubtype(SubType.AURA, game)) {
|
||||
SpellAbility spellAbility = null;
|
||||
UUID controller = null;
|
||||
Permanent attachmentPermanent = game.getPermanent(attachment.getId());
|
||||
if (attachmentPermanent != null) {
|
||||
spellAbility = attachmentPermanent.getSpellAbility(); // Permanent's SpellAbility might be modified, so if possible use that one
|
||||
controller = attachmentPermanent.getControllerId();
|
||||
} else { // Used for checking if it can be attached from the graveyard, such as Unfinished Business
|
||||
Card attachmentCard = game.getCard(attachment.getId());
|
||||
if (attachmentCard != null) {
|
||||
spellAbility = attachmentCard.getSpellAbility();
|
||||
if (source != null) {
|
||||
controller = source.getControllerId();
|
||||
} else {
|
||||
controller = attachmentCard.getControllerOrOwnerId();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (controller != null && spellAbility != null && !spellAbility.getTargets().isEmpty()){
|
||||
// Line of code below functionally gets the target of the aura's Enchant ability, then compares to this permanent. Enchant improperly implemented in XMage, see #9583
|
||||
// Note: stillLegalTarget used exclusively to account for Dream Leash. Can be made canTarget in the event that that card is rewritten (and "stillLegalTarget" removed from TargetImpl).
|
||||
canAttach &= spellAbility.getTargets().get(0).copy().withNotTarget(true).stillLegalTarget(controller, this.getId(), source, game);
|
||||
}
|
||||
}
|
||||
|
||||
return !canAttach || game.getContinuousEffects().preventedByRuleModification(new StayAttachedEvent(this.getId(), attachment.getId(), source), null, game, silentMode);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2803,7 +2803,7 @@ public abstract class GameImpl implements Game {
|
|||
if (attachedTo != null) {
|
||||
for (Ability ability : perm.getAbilities(this)) {
|
||||
if (ability instanceof AttachableToRestrictedAbility) {
|
||||
if (!((AttachableToRestrictedAbility) ability).canEquip(attachedTo, null, this)) {
|
||||
if (!((AttachableToRestrictedAbility) ability).canEquip(attachedTo.getId(), null, this)) {
|
||||
attachedTo = null;
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue