Support for Midnight Crusader Shuttle (#4478)

This commit is contained in:
tool4ever
2024-01-04 16:47:58 +01:00
committed by GitHub
parent 2933922572
commit 1e135e8d3b
19 changed files with 44 additions and 88 deletions

View File

@@ -344,12 +344,11 @@ public class ChangeZoneAi extends SpellAbilityAi {
Iterable<Player> pDefined = Lists.newArrayList(source.getController());
final TargetRestrictions tgt = sa.getTargetRestrictions();
if (tgt != null && tgt.canTgtPlayer()) {
sa.resetTargets();
boolean isCurse = sa.isCurse();
if (isCurse && sa.canTarget(opponent)) {
sa.resetTargets();
sa.getTargets().add(opponent);
} else if (!isCurse && sa.canTarget(ai)) {
sa.resetTargets();
sa.getTargets().add(ai);
}
if (!sa.isTargetNumberValid()) {

View File

@@ -611,46 +611,41 @@ public abstract class SpellAbilityEffect {
}
}
protected static boolean addToCombat(Card c, Player controller, SpellAbility sa, String attackingParam, String blockingParam) {
protected static boolean addToCombat(Card c, SpellAbility sa, String attackingParam, String blockingParam) {
final Card host = sa.getHostCard();
final Game game = controller.getGame();
final Game game = host.getGame();
if (!c.isCreature() || !game.getPhaseHandler().inCombat()) {
return false;
}
boolean combatChanged = false;
final Combat combat = game.getCombat();
if (sa.hasParam(attackingParam) && combat.getAttackingPlayer().equals(controller)) {
if (sa.hasParam(attackingParam) && combat.getAttackingPlayer().equals(c.getController())) {
String attacking = sa.getParam(attackingParam);
GameEntity defender = null;
FCollection<GameEntity> defs = null;
// important to update defenders here, maybe some PW got removed
combat.initConstraints();
if (sa.hasParam("ChoosePlayerOrPlaneswalker")) {
PlayerCollection defendingPlayers = AbilityUtils.getDefinedPlayers(sa.hasParam("ForEach") ? c : host, attacking, sa);
defs = new FCollection<>(defendingPlayers);
defs.addAll(Iterables.filter(combat.getDefendingPlaneswalkers(), CardPredicates.isControlledByAnyOf(defendingPlayers)));
} else if ("True".equalsIgnoreCase(attacking)) {
if ("True".equalsIgnoreCase(attacking)) {
defs = (FCollection<GameEntity>) combat.getDefenders();
} else {
defs = AbilityUtils.getDefinedEntities(host, attacking, sa);
defs = AbilityUtils.getDefinedEntities(sa.hasParam("ForEach") ? c : host, attacking.split(","), sa);
}
if (defs != null) {
Map<String, Object> params = Maps.newHashMap();
params.put("Attacker", c);
Player chooser;
if (sa.hasParam("Chooser")) {
chooser = Iterables.getFirst(AbilityUtils.getDefinedPlayers(host, sa.getParam("Chooser"), sa), null);
} else {
chooser = controller;
}
defender = chooser.getController().chooseSingleEntityForEffect(defs, sa,
defender = sa.getActivatingPlayer().getController().chooseSingleEntityForEffect(defs, sa,
Localizer.getInstance().getMessage("lblChooseDefenderToAttackWithCard", CardTranslation.getTranslatedName(c.getName())), false, params);
}
if (defender != null) {
final GameEntity originalDefender = combat.getDefenderByAttacker(c);
if (defender != null &&
(originalDefender == null || !originalDefender.equals(defender))) {
// we might be reselecting
combat.removeFromCombat(c);
combat.addAttacker(c, defender);
combat.getBandOfAttacker(c).setBlocked(false);
combatChanged = true;

View File

@@ -1,16 +1,10 @@
package forge.game.ability.effects;
import java.util.Map;
import com.google.common.collect.Maps;
import forge.game.Game;
import forge.game.GameEntity;
import forge.game.ability.AbilityKey;
import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card;
import forge.game.combat.AttackingBand;
import forge.game.combat.Combat;
import forge.game.event.GameEventCombatChanged;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
@@ -18,7 +12,6 @@ import forge.game.spellability.SpellAbilityStackInstance;
import forge.util.CardTranslation;
import forge.util.Lang;
import forge.util.Localizer;
import forge.util.collect.FCollection;
public class ChangeCombatantsEffect extends SpellAbilityEffect {
@@ -36,33 +29,24 @@ public class ChangeCombatantsEffect extends SpellAbilityEffect {
@Override
public void resolve(SpellAbility sa) {
boolean isCombatChanged = false;
final boolean isOptional = sa.hasParam("Optional");
final Player activator = sa.getActivatingPlayer();
final Game game = activator.getGame();
// TODO: may expand this effect for defined blocker (False Orders, General Jarkeld, Sorrow's Path, Ydwen Efreet)
for (final Card c : getTargetCards(sa)) {
String cardString = CardTranslation.getTranslatedName(c.getName()) + " (" + c.getId() + ")";
boolean isOptional = sa.hasParam("Optional");
if (isOptional && !activator.getController().confirmAction(sa, null,
Localizer.getInstance().getMessage("lblChangeCombatantOption", cardString), null)) {
continue;
}
final Combat combat = game.getCombat();
final GameEntity originalDefender = combat.getDefenderByAttacker(c);
final FCollection<GameEntity> defs = new FCollection<>(sa.hasParam("PlayerOnly") ? combat.getDefendingPlayers() : combat.getDefenders());
final GameEntity originalDefender = game.getCombat().getDefenderByAttacker(c);
String title = Localizer.getInstance().getMessage("lblChooseDefenderToAttackWithCard", cardString);
Map<String, Object> params = Maps.newHashMap();
params.put("Attacker", c);
if (addToCombat(c, sa, "Attacking", "Blocking")) {
isCombatChanged = true;
GameEntity defender = game.getCombat().getDefenderByAttacker(c);
final GameEntity defender = activator.getController().chooseSingleEntityForEffect(defs, sa, title, false, params);
if (originalDefender != null && !originalDefender.equals(defender)) {
AttackingBand ab = combat.getBandOfAttacker(c);
if (ab != null) {
combat.unregisterAttacker(c, ab);
ab.removeAttacker(c);
}
combat.addAttacker(c, defender);
// retarget triggers to the new defender (e.g. Ulamog, Ceaseless Hunger + Portal Mage)
for (SpellAbilityStackInstance si : game.getStack()) {
if (si.isTrigger() && c.equals(si.getSourceCard())
@@ -75,7 +59,6 @@ public class ChangeCombatantsEffect extends SpellAbilityEffect {
}
}
}
isCombatChanged = true;
}
}

View File

@@ -673,7 +673,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
if (sa.hasParam("LeaveBattlefield")) {
addLeaveBattlefieldReplacement(movedCard, sa, sa.getParam("LeaveBattlefield"));
}
if (addToCombat(movedCard, movedCard.getController(), sa, "Attacking", "Blocking")) {
if (addToCombat(movedCard, sa, "Attacking", "Blocking")) {
combatChanged = true;
}
if (sa.isNinjutsu()) {
@@ -1369,7 +1369,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
}
}
if (addToCombat(c, c.getController(), sa, "Attacking", "Blocking")) {
if (addToCombat(c, sa, "Attacking", "Blocking")) {
combatChanged = true;
}

View File

@@ -18,7 +18,6 @@ import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.event.GameEventCardStatsChanged;
import forge.game.event.GameEventCombatChanged;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import forge.game.trigger.TriggerType;
@@ -149,7 +148,6 @@ public class ControlGainEffect extends SpellAbilityEffect {
return;
}
boolean combatChanged = false;
CardCollection untapped = new CardCollection();
for (Card tgtC : tgtCards) {
if (!tgtC.isInPlay() || !tgtC.canBeControlledBy(newController)) {
@@ -176,25 +174,10 @@ public class ControlGainEffect extends SpellAbilityEffect {
if (tgtC.untap(true)) untapped.add(tgtC);
}
final List<String> kws = Lists.newArrayList();
final List<String> hiddenKws = Lists.newArrayList();
if (null != keywords) {
for (final String kw : keywords) {
if (kw.startsWith("HIDDEN")) {
hiddenKws.add(kw.substring(7));
} else {
kws.add(kw);
}
}
}
if (!kws.isEmpty()) {
tgtC.addChangedCardKeywords(kws, Lists.newArrayList(), false, tStamp, 0);
if (keywords != null) {
tgtC.addChangedCardKeywords(keywords, Lists.newArrayList(), false, tStamp, 0);
game.fireEvent(new GameEventCardStatsChanged(tgtC));
}
if (!hiddenKws.isEmpty()) {
tgtC.addHiddenExtrinsicKeywords(tStamp, 0, hiddenKws);
}
if (remember && !source.isRemembered(tgtC)) {
source.addRemembered(tgtC);
@@ -244,7 +227,6 @@ public class ControlGainEffect extends SpellAbilityEffect {
@Override
public void run() {
tgtC.removeHiddenExtrinsicKeywords(tStamp, 0);
tgtC.removeChangedCardKeywords(tStamp, 0);
}
};
@@ -252,11 +234,8 @@ public class ControlGainEffect extends SpellAbilityEffect {
}
game.getAction().controllerChangeZoneCorrection(tgtC);
if (addToCombat(tgtC, tgtC.getController(), sa, "Attacking", "Blocking")) {
combatChanged = true;
}
} // end foreach target
if (!untapped.isEmpty()) {
final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
final Map<Player, CardCollection> map = Maps.newHashMap();
@@ -264,11 +243,6 @@ public class ControlGainEffect extends SpellAbilityEffect {
runParams.put(AbilityKey.Map, map);
game.getTriggerHandler().runTrigger(TriggerType.UntapAll, runParams, false);
}
if (combatChanged) {
game.updateCombatForView();
game.fireEvent(new GameEventCombatChanged());
}
}
/**

View File

@@ -411,7 +411,7 @@ public class DigEffect extends SpellAbilityEffect {
}
c = game.getAction().moveTo(c.getController().getZone(destZone1), c, sa, moveParams);
if (destZone1.equals(ZoneType.Battlefield)) {
if (addToCombat(c, c.getController(), sa, "Attacking", "Blocking")) {
if (addToCombat(c, sa, "Attacking", "Blocking")) {
combatChanged = true;
}
} else if (destZone1.equals(ZoneType.Exile)) {

View File

@@ -239,7 +239,7 @@ public class DigUntilEffect extends SpellAbilityEffect {
c.setTapped(true);
}
m = game.getAction().moveTo(c.getController().getZone(foundDest), c, sa, moveParams);
if (addToCombat(c, c.getController(), sa, "Attacking", "Blocking")) {
if (addToCombat(c, sa, "Attacking", "Blocking")) {
combatChanged = true;
}
} else if (sa.hasParam("NoMoveFound")) {

View File

@@ -65,7 +65,7 @@ public class MeldEffect extends SpellAbilityEffect {
PlayerZoneBattlefield bf = (PlayerZoneBattlefield)controller.getZone(ZoneType.Battlefield);
bf.addToMelded(secondary);
Card movedCard = game.getAction().changeZone(primary.getZone(), bf, primary, 0, sa);
if (addToCombat(movedCard, movedCard.getController(), sa, "Attacking", "Blocking")) {
if (addToCombat(movedCard, sa, "Attacking", "Blocking")) {
game.updateCombatForView();
game.fireEvent(new GameEventCombatChanged());
}

View File

@@ -185,7 +185,7 @@ public abstract class TokenEffectBase extends SpellAbilityEffect {
addSelfTrigger(sa, sa.getParam("AtEOTTrig"), moved);
}
if (addToCombat(moved, tok.getController(), sa, "TokenAttacking", "TokenBlocking")) {
if (addToCombat(moved, sa, "TokenAttacking", "TokenBlocking")) {
combatChanged.setTrue();
}

View File

@@ -1566,8 +1566,8 @@ public class CardFactoryUtil {
final String actualTrigger = "Mode$ Attacks | ValidCard$ Card.Self | Secondary$ True"
+ " | TriggerDescription$ Myriad (" + inst.getReminderText() + ")";
final String copyStr = "DB$ CopyPermanent | Defined$ Self | TokenTapped$ True | Optional$ True | TokenAttacking$ Remembered"
+ "| ForEach$ OppNonDefendingPlayer | ChoosePlayerOrPlaneswalker$ True | AtEOT$ ExileCombat | CleanupForEach$ True";
final String copyStr = "DB$ CopyPermanent | Defined$ Self | TokenTapped$ True | Optional$ True | TokenAttacking$ Player.IsRemembered,Valid Planeswalker.ControlledBy Remembered"
+ "| ForEach$ OppNonDefendingPlayer | AtEOT$ ExileCombat | CleanupForEach$ True";
final SpellAbility copySA = AbilityFactory.getAbility(copyStr, card);
copySA.setIntrinsic(intrinsic);

View File

@@ -241,6 +241,10 @@ public class CardProperty {
if (!lp.contains(card.getProtectingPlayer())) {
return false;
}
} else if (property.equals("Defending")) {
if (game.getCombat() == null || !game.getCombat().getAttackersAndDefenders().values().contains(card)) {
return false;
}
} else if (property.startsWith("DefendingPlayer")) {
Player p = property.endsWith("Ctrl") ? controller : card.getOwner();
if (!game.getPhaseHandler().inCombat()) {

View File

@@ -7,6 +7,6 @@ S:Mode$ Continuous | EffectZone$ All | CharacteristicDefining$ True | SetPower$
SVar:X:Count$Valid Creature.YouCtrl
T:Mode$ AttackersDeclared | AttackingPlayer$ You | Execute$ DBRepeat | TriggerZones$ Battlefield | TriggerDescription$ Whenever you attack, for each opponent, create a 1/1 white Human creature token that's tapped and attacking that player or a planeswalker they control.
SVar:DBRepeat:DB$ RepeatEach | RepeatPlayers$ Opponent | ChangeZoneTable$ True | RepeatSubAbility$ DBToken
SVar:DBToken:DB$ Token | TokenAmount$ 1 | TokenScript$ w_1_1_human | TokenTapped$ True | TokenAttacking$ Remembered | ChoosePlayerOrPlaneswalker$ True | TokenOwner$ You
SVar:DBToken:DB$ Token | TokenAmount$ 1 | TokenScript$ w_1_1_human | TokenTapped$ True | TokenAttacking$ Player.IsRemembered,Valid Planeswalker.ControlledBy Remembered | TokenOwner$ You
DeckHas:Ability$Token
Oracle:Vigilance\nAdeline, Resplendent Cathar's power is equal to the number of creatures you control.\nWhenever you attack, for each opponent, create a 1/1 white Human creature token that's tapped and attacking that player or a planeswalker they control.

View File

@@ -5,6 +5,6 @@ PT:0/0
K:etbCounter:P1P1:X
SVar:X:Count$xPaid
A:AB$ PutCounter | Cost$ 2 | Activator$ Player | IsPresent$ Card.Self+attackingYou | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1 | SubAbility$ DBReselect | ActivationPhases$ Declare Attackers | AILogic$ AlwaysWithNoTgt | SpellDescription$ Put a +1/+1 counter on CARDNAME, then you may reselect which player CARDNAME is attacking. Only the player CARDNAME is attacking may activate this ability and only during the declare attackers step. (It can't attack its controller.)
SVar:DBReselect:DB$ ChangeCombatants | Defined$ Self | AILogic$ WeakestOppExceptCtrl | PlayerOnly$ True
SVar:DBReselect:DB$ ChangeCombatants | Defined$ Self | AILogic$ WeakestOppExceptCtrl | Attacking$ Player.OpponentOf CardController
DeckHas:Ability$Counters
Oracle:Capricopian enters the battlefield with X +1/+1 counters on it.\n{2}: Put a +1/+1 counter on Capricopian, then you may reselect which player Capricopian is attacking. Only the player Capricopian is attacking may activate this ability and only during the declare attackers step. (It can't attack its controller.)

View File

@@ -3,7 +3,7 @@ ManaCost:2 R G
Types:Legendary Creature Human Scout
PT:1/4
T:Mode$ Attacks | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigDig | TriggerDescription$ Whenever CARDNAME attacks, reveal the top card of your library. If it's a creature card, put it onto the battlefield tapped and attacking defending player or a planeswalker they control. Otherwise, put that card into your hand. When you put a creature card onto the battlefield this way, it fights CARDNAME.
SVar:TrigDig:DB$ Dig | DigNum$ 1 | ChangeNum$ All | Optional$ True | Reveal$ True | ChangeValid$ Creature | DestinationZone$ Battlefield | DestinationZone2$ Hand | Tapped$ True | Attacking$ DefendingPlayer | ChoosePlayerOrPlaneswalker$ True | RememberChanged$ True | SubAbility$ DBImmediateTriggerCheck
SVar:TrigDig:DB$ Dig | DigNum$ 1 | ChangeNum$ All | Optional$ True | Reveal$ True | ChangeValid$ Creature | DestinationZone$ Battlefield | DestinationZone2$ Hand | Tapped$ True | Attacking$ DefendingPlayer,Valid Planeswalker.ControlledBy DefendingPlayer | RememberChanged$ True | SubAbility$ DBImmediateTriggerCheck
SVar:DBImmediateTriggerCheck:DB$ ImmediateTrigger | Execute$ DBFight | ConditionDefined$ Remembered | ConditionPresent$ Creature | ConditionCompare$ GE1 | TriggerDescription$ When you put a creature card onto the battlefield this way, it fights Hans Eriksson.
SVar:DBFight:DB$ Fight | Defined$ Remembered | ExtraDefined$ Self | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True

View File

@@ -3,7 +3,7 @@ ManaCost:2 U
Types:Artifact
K:Flash
T:Mode$ ChangesZone | Phase$ Declare Attackers | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigChangeAttacker | OptionalDecider$ You | TriggerDescription$ When CARDNAME enters the battlefield during the declare attackers step, you may reselect which player or permanent target attacking creature is attacking. (It can't attack its controller or their permanents.)
SVar:TrigChangeAttacker:DB$ ChangeCombatants | ValidTgts$ Creature.attacking | TgtPrompt$ Select target attacking creature
SVar:TrigChangeAttacker:DB$ ChangeCombatants | ValidTgts$ Creature.attacking | TgtPrompt$ Select target attacking creature | Attacking$ True
AI:RemoveDeck:All
A:AB$ Mana | Cost$ T | Produced$ U | SpellDescription$ Add {U}.
Oracle:Flash\nWhen Misleading Signpost enters the battlefield during the declare attackers step, you may reselect which player or permanent target attacking creature is attacking. (It can't attack its controller or their permanents.)\n{T}: Add {U}.

View File

@@ -4,6 +4,6 @@ Types:Creature Human Wizard
PT:2/2
K:Flash
T:Mode$ ChangesZone | Phase$ Declare Attackers | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigChangeAttacker | OptionalDecider$ You | TriggerDescription$ When CARDNAME enters the battlefield during the declare attackers step, you may reselect which player or permanent target attacking creature is attacking. (It can't attack its controller or their permanents.)
SVar:TrigChangeAttacker:DB$ ChangeCombatants | ValidTgts$ Creature.attacking | TgtPrompt$ Select target attacking creature
SVar:TrigChangeAttacker:DB$ ChangeCombatants | ValidTgts$ Creature.attacking | TgtPrompt$ Select target attacking creature | Attacking$ True
AI:RemoveDeck:All
Oracle:Flash\nWhen Portal Mage enters the battlefield during the declare attackers step, you may reselect which player or permanent target attacking creature is attacking. (It can't attack its controller or their permanents.)

View File

@@ -4,6 +4,8 @@ Types:Legendary Creature Minotaur Warrior
PT:5/5
S:Mode$ MinMaxBlocker | ValidCard$ Card.Self | Max$ 1 | Description$ CARDNAME can't be blocked by more than one creature.
T:Mode$ AttackersDeclared | AttackingPlayer$ Player.Opponent | Execute$ TrigGainControl | TriggerZones$ Battlefield | OptionalDecider$ You | IsPresent$ Card.Self+tapped | TriggerDescription$ Whenever an opponent attacks with one or more creatures, if NICKNAME is tapped, you may have that opponent gain control of NICKNAME until end of combat. If you do, choose a player or planeswalker that opponent is attacking. NICKNAME is attacking that player or planeswalker.
SVar:TrigGainControl:DB$ GainControl | Defined$ Self | NewController$ TriggeredAttackingPlayer | LoseControl$ EndOfCombat | Attacking$ Player.Defending | Chooser$ You | ChoosePlayerOrPlaneswalker$ True
SVar:TrigGainControl:DB$ GainControl | Defined$ Self | NewController$ TriggeredAttackingPlayer | LoseControl$ EndOfCombat | RememberControlled$ True | SubAbility$ DBAttack
SVar:DBAttack:DB$ ChangeCombatants | Defined$ Remembered | Attacking$ Player.Defending,Valid Planeswalker.Defending | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
AI:RemoveDeck:All
Oracle:Tahngarth, First Mate can't be blocked by more than one creature.\nWhenever an opponent attacks with one or more creatures, if Tahngarth is tapped, you may have that opponent gain control of Tahngarth until end of combat. If you do, choose a player or planeswalker that opponent is attacking. Tahngarth is attacking that player or planeswalker.

View File

@@ -5,7 +5,6 @@ PT:4/4
K:Flash
K:Flying
T:Mode$ ChangesZone | Phase$ Declare Attackers | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigEachAttacker | TriggerDescription$ When CARDNAME enters the battlefield during the declare attackers step, for each attacking creature, you may reselect which player or permanent that creature is attacking. (It can't attack its controller or their permanents.)
SVar:TrigEachAttacker:DB$ RepeatEach | RepeatCards$ Creature.attacking | RepeatSubAbility$ DBChangeAttacker
SVar:DBChangeAttacker:DB$ ChangeCombatants | Defined$ Remembered | Optional$ True
SVar:TrigEachAttacker:DB$ ChangeCombatants | Defined$ Valid Creature.attacking | Optional$ True | Attacking$ True
AI:RemoveDeck:All
Oracle:Flash\nFlying\nWhen Windshaper Planetar enters the battlefield during the declare attackers step, for each attacking creature, you may reselect which player or permanent that creature is attacking. (It can't attack its controller or their permanents.)

View File

@@ -4,7 +4,7 @@ Types:Legendary Creature Human Pirate
PT:4/3
K:Flying
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigBorrow | TriggerDescription$ Whenever CARDNAME attacks, look at defending player's hand. You may put a creature card from it onto the battlefield under your control tapped and attacking that player or a planeswalker they control. Return that creature to its owner's hand at the beginning of the next end step.
SVar:TrigBorrow:DB$ ChangeZone | ChangeNum$ 1 | DefinedPlayer$ TriggeredDefendingPlayer | Chooser$ You | ChangeType$ Creature | Origin$ Hand | Destination$ Battlefield | GainControl$ True | Tapped$ True | Attacking$ DefendingPlayer | ChoosePlayerOrPlaneswalker$ True | RememberChanged$ True | SubAbility$ DBDelayTrig
SVar:TrigBorrow:DB$ ChangeZone | ChangeNum$ 1 | DefinedPlayer$ TriggeredDefendingPlayer | Chooser$ You | ChangeType$ Creature | Origin$ Hand | Destination$ Battlefield | GainControl$ True | Tapped$ True | Attacking$ DefendingPlayer,Valid Planeswalker.ControlledBy DefendingPlayer | RememberChanged$ True | SubAbility$ DBDelayTrig
SVar:DBDelayTrig:DB$ DelayedTrigger | Mode$ Phase | Phase$ End of Turn | ValidPlayer$ Player | RememberObjects$ RememberedLKI | Execute$ DBChange | StackDescription$ None | SubAbility$ DBCleanup | TriggerDescription$ Return that creature to its owner's hand at the beginning of the next end step.
SVar:DBChange:DB$ ChangeZone | Defined$ DelayTriggerRememberedLKI | Origin$ Battlefield | Destination$ Hand
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True