mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 04:08:01 +00:00
Support scripted switching to different trigger context (#3349)
* Support scripted switching to different trigger context
This commit is contained in:
@@ -86,10 +86,11 @@ public class AbilityUtils {
|
||||
// But then we only need update one function at a time once the casting is
|
||||
// everywhere.
|
||||
// Probably will move to One function solution sometime in the future
|
||||
public static CardCollection getDefinedCards(final Card hostCard, final String def, final CardTraitBase sa) {
|
||||
public static CardCollection getDefinedCards(final Card hostCard, final String def, CardTraitBase sa) {
|
||||
CardCollection cards = new CardCollection();
|
||||
String changedDef = (def == null) ? "Self" : applyAbilityTextChangeEffects(def, sa); // default to Self
|
||||
final String[] incR = changedDef.split("\\.", 2);
|
||||
sa = adjustTriggerContext(incR, sa);
|
||||
String defined = incR[0];
|
||||
final Game game = hostCard.getGame();
|
||||
|
||||
@@ -433,7 +434,7 @@ public class AbilityUtils {
|
||||
public static int calculateAmount(final Card card, String amount, final CardTraitBase ability) {
|
||||
return calculateAmount(card, amount, ability, false);
|
||||
}
|
||||
public static int calculateAmount(final Card card, String amount, final CardTraitBase ability, boolean maxto) {
|
||||
public static int calculateAmount(final Card card, String amount, CardTraitBase ability, boolean maxto) {
|
||||
// return empty strings and constants
|
||||
if (StringUtils.isBlank(amount)) { return 0; }
|
||||
if (card == null) { return 0; }
|
||||
@@ -508,6 +509,8 @@ public class AbilityUtils {
|
||||
// modify amount string for text changes
|
||||
calcX[1] = applyAbilityTextChangeEffects(calcX[1], ability);
|
||||
|
||||
ability = adjustTriggerContext(calcX, ability);
|
||||
|
||||
Integer val = null;
|
||||
if (calcX[0].startsWith("Count")) {
|
||||
val = xCount(card, calcX[1], ability);
|
||||
@@ -986,16 +989,15 @@ public class AbilityUtils {
|
||||
* @return a {@link java.util.ArrayList} object.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static PlayerCollection getDefinedPlayers(final Card card, final String def, final CardTraitBase sa) {
|
||||
public static PlayerCollection getDefinedPlayers(final Card card, final String def, CardTraitBase sa) {
|
||||
final PlayerCollection players = new PlayerCollection();
|
||||
final Player player = sa instanceof SpellAbility ? ((SpellAbility)sa).getActivatingPlayer() : card.getController();
|
||||
final Game game = card == null ? null : card.getGame();
|
||||
String changedDef = (def == null) ? "You" : applyAbilityTextChangeEffects(def, sa); // default to Self
|
||||
final String[] incR = changedDef.split("\\.", 2);
|
||||
sa = adjustTriggerContext(incR, sa);
|
||||
String defined = incR[0];
|
||||
|
||||
final Game game = card == null ? null : card.getGame();
|
||||
|
||||
final Player player = sa instanceof SpellAbility ? ((SpellAbility)sa).getActivatingPlayer() : card.getController();
|
||||
|
||||
if (defined.equals("Self") || defined.equals("TargetedCard") || defined.equals("ThisTargetedCard")
|
||||
|| defined.startsWith("Valid") || getPaidCards(sa, defined) != null || defined.equals("TargetedSource")
|
||||
|| defined.startsWith("CardUID_")) {
|
||||
@@ -3887,4 +3889,20 @@ public class AbilityUtils {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static CardTraitBase adjustTriggerContext(String[] def, final CardTraitBase ctb) {
|
||||
if (def[0].startsWith("Spawner>") && ctb instanceof SpellAbility) {
|
||||
Trigger trig = ((SpellAbility) ctb).getTrigger();
|
||||
if (trig == null) {
|
||||
return ctb;
|
||||
}
|
||||
SpellAbility spawner = trig.getSpawningAbility();
|
||||
if (spawner == null) {
|
||||
return ctb;
|
||||
}
|
||||
def[0] = def[0].substring(8);
|
||||
return spawner;
|
||||
}
|
||||
return ctb;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,10 +81,6 @@ public class DelayedTriggerEffect extends SpellAbilityEffect {
|
||||
overridingSA.setSVar("StoredTransform", String.valueOf(host.getTransformedTimestamp()));
|
||||
}
|
||||
|
||||
if (sa.hasParam("CopyTriggeringObjects")) {
|
||||
overridingSA.setTriggeringObjects(sa.getTriggeringObjects());
|
||||
}
|
||||
|
||||
delTrig.setOverridingAbility(overridingSA);
|
||||
}
|
||||
final TriggerHandler trigHandler = game.getTriggerHandler();
|
||||
|
||||
@@ -70,10 +70,6 @@ public class ImmediateTriggerEffect extends SpellAbilityEffect {
|
||||
((AbilitySub)overridingSA).setParent(null);
|
||||
}
|
||||
|
||||
if (sa.hasParam("CopyTriggeringObjects")) {
|
||||
overridingSA.setTriggeringObjects(sa.getTriggeringObjects());
|
||||
}
|
||||
|
||||
immediateTrig.setOverridingAbility(overridingSA);
|
||||
}
|
||||
|
||||
|
||||
@@ -186,7 +186,6 @@ public class CardFactory {
|
||||
copySA = getCopiedTriggeredAbility((WrappedAbility)targetSA, c, controller);
|
||||
} else {
|
||||
copySA = targetSA.copy(c, controller, false);
|
||||
c.setCastSA(copySA);
|
||||
// need to copy keyword
|
||||
if (targetSA.getKeyword() != null) {
|
||||
KeywordInterface kw = targetSA.getKeyword().copy(c, false);
|
||||
@@ -206,13 +205,13 @@ public class CardFactory {
|
||||
if (copySA instanceof Spell) {
|
||||
Spell spell = (Spell) copySA;
|
||||
spell.setCastFaceDown(false);
|
||||
c.setCastSA(copySA);
|
||||
}
|
||||
|
||||
//remove all costs
|
||||
if (!copySA.isTrigger()) {
|
||||
copySA.setPayCosts(new Cost("", targetSA.isAbility()));
|
||||
}
|
||||
copySA.setActivatingPlayer(controller);
|
||||
|
||||
return copySA;
|
||||
}
|
||||
|
||||
@@ -1072,7 +1072,6 @@ public class PhaseHandler implements java.io.Serializable {
|
||||
triggerList.put(originZone.getZoneType(), currentZone.getZoneType(), saHost);
|
||||
triggerList.triggerChangesZoneAll(game, sa);
|
||||
}
|
||||
|
||||
}
|
||||
game.copyLastState();
|
||||
loopCount++;
|
||||
|
||||
@@ -5,7 +5,7 @@ PT:3/3
|
||||
K:Ninjutsu:2 B
|
||||
K:etbCounter:Menace:1
|
||||
T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | Execute$ TrigImmediateTrig | CombatDamage$ True | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, you may remove a menace counter from it. When you do, that player reveals their hand and you choose a nonland card from it. Exile that card.
|
||||
SVar:TrigImmediateTrig:AB$ ImmediateTrigger | Cost$ SubCounter<1/Menace> | Execute$ TrigReveal | CopyTriggeringObjects$ True | TriggerDescription$ When you do, that player reveals their hand and you choose a nonland card from it. Exile that card.
|
||||
SVar:TrigReveal:DB$ RevealHand | Defined$ TriggeredTarget | SubAbility$ DBExile
|
||||
SVar:DBExile:DB$ ChangeZone | Origin$ Hand | Destination$ Exile | DefinedPlayer$ TriggeredTarget | Chooser$ You | ChangeType$ Card.nonLand | ChangeNum$ 1 | IsCurse$ True
|
||||
SVar:TrigImmediateTrig:AB$ ImmediateTrigger | Cost$ SubCounter<1/Menace> | Execute$ TrigReveal | TriggerDescription$ When you do, that player reveals their hand and you choose a nonland card from it. Exile that card.
|
||||
SVar:TrigReveal:DB$ RevealHand | Defined$ Spawner>TriggeredTarget | SubAbility$ DBExile
|
||||
SVar:DBExile:DB$ ChangeZone | Origin$ Hand | Destination$ Exile | DefinedPlayer$ Spawner>TriggeredTarget | Chooser$ You | ChangeType$ Card.nonLand | ChangeNum$ 1 | IsCurse$ True
|
||||
Oracle:Ninjutsu {2}{B}\nBiting-Palm Ninja enters the battlefield with a menace counter on it.\nWhenever Biting-Palm Ninja deals combat damage to a player, you may remove a menace counter from it. When you do, that player reveals their hand and you choose a nonland card from it. Exile that card.
|
||||
|
||||
@@ -4,8 +4,8 @@ Types:Creature Human Ninja
|
||||
PT:2/1
|
||||
K:Ninjutsu:1 B
|
||||
T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | Execute$ TrigImmediateTrig | CombatDamage$ True | OptionalDecider$ You | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, you may discard a creature card. When you do, destroy target creature or planeswalker that player controls.
|
||||
SVar:TrigImmediateTrig:AB$ ImmediateTrigger | Cost$ Discard<1/Creature> | Execute$ TrigDestroy | CopyTriggeringObjects$ True | TriggerDescription$ When you do, destroy target creature or planeswalker that player controls.
|
||||
SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Creature.ControlledBy TriggeredTarget,Planeswalker.ControlledBy TriggeredTarget | TgtPrompt$ Select target creature or planeswalker damaged player controls
|
||||
SVar:TrigImmediateTrig:AB$ ImmediateTrigger | Cost$ Discard<1/Creature> | Execute$ TrigDestroy | TriggerDescription$ When you do, destroy target creature or planeswalker that player controls.
|
||||
SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Creature.ControlledBy Spawner>TriggeredTarget,Planeswalker.ControlledBy Spawner>TriggeredTarget | TgtPrompt$ Select target creature or planeswalker damaged player controls
|
||||
DeckHas:Ability$Discard
|
||||
SVar:AIPreference:DiscardCost$Creature.cmcLE3
|
||||
Oracle:Ninjutsu {1}{B} ({1}{B}, Return an unblocked attacker you control to hand: Put this card onto the battlefield from your hand tapped and attacking.)\nWhenever Dokuchi Silencer deals combat damage to a player, you may discard a creature card. When you do, destroy target creature or planeswalker that player controls.
|
||||
|
||||
@@ -5,8 +5,8 @@ PT:3/4
|
||||
K:Reach
|
||||
K:Partner
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.Other+YouCtrl | Execute$ TrigPayCost | TriggerZones$ Battlefield | TriggerDescription$ Whenever another creature enters the battlefield under your control, you may pay {2}. When you do, that creature deals damage equal to its power to target creature.
|
||||
SVar:TrigPayCost:AB$ ImmediateTrigger | Cost$ 2 | Execute$ TrigDealDamage | CopyTriggeringObjects$ True | TriggerDescription$ When you pay {2}, that creature deals damage equal to its power to target creature.
|
||||
SVar:TrigDealDamage:DB$ DealDamage | DamageSource$ TriggeredCardLKICopy | NumDmg$ X | ValidTgts$ Creature
|
||||
SVar:X:TriggeredCard$CardPower
|
||||
SVar:TrigPayCost:AB$ ImmediateTrigger | Cost$ 2 | Execute$ TrigDealDamage | TriggerDescription$ When you pay {2}, that creature deals damage equal to its power to target creature.
|
||||
SVar:TrigDealDamage:DB$ DealDamage | DamageSource$ Spawner>TriggeredCardLKICopy | NumDmg$ X | ValidTgts$ Creature
|
||||
SVar:X:Spawner>TriggeredCard$CardPower
|
||||
DeckNeeds:Type$Creature
|
||||
Oracle:Reach\nWhenever another creature enters the battlefield under your control, you may pay {2}. When you do, that creature deals damage equal to its power to target creature.\nPartner (You can have two commanders if both have partner.)
|
||||
|
||||
@@ -3,10 +3,10 @@ ManaCost:2 R R
|
||||
Types:Creature Manticore
|
||||
PT:4/3
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ DBTrigger | TriggerDescription$ When CARDNAME enters the battlefield, you may sacrifice another creature. When you do, CARDNAME deals damage equal to that creature's power to target creature or player.
|
||||
SVar:DBTrigger:AB$ ImmediateTrigger | Cost$ Sac<1/Creature.Other/another creature> | Execute$ TrigDamage | AILogic$ SacForDamage | RememberObjects$ Sacrificed | TriggerDescription$ When you do, CARDNAME deals damage equal to that creature's power to any target.
|
||||
SVar:DBTrigger:AB$ ImmediateTrigger | Cost$ Sac<1/Creature.Other/another creature> | Execute$ TrigDamage | AILogic$ SacForDamage | TriggerDescription$ When you do, CARDNAME deals damage equal to that creature's power to any target.
|
||||
SVar:TrigDamage:DB$ DealDamage | ValidTgts$ Any | NumDmg$ XPower
|
||||
K:Embalm:5 R
|
||||
SVar:XPower:TriggerRemembered$CardPower
|
||||
SVar:XPower:Spawner>Sacrificed$CardPower
|
||||
SVar:AIPreferenceParams:CreatureEvalThreshold$ 200
|
||||
DeckHas:Ability$Token|Sacrifice
|
||||
Oracle:When Heart-Piercer Manticore enters the battlefield, you may sacrifice another creature. When you do, Heart-Piercer Manticore deals damage equal to that creature's power to any target.\nEmbalm {5}{R} ({5}{R}, Exile this card from your graveyard: Create a token that's a copy of it, except it's a white Zombie Manticore with no mana cost. Embalm only as a sorcery.)
|
||||
|
||||
@@ -5,12 +5,12 @@ K:Enchant creature
|
||||
A:SP$ Attach | Cost$ W W W | ValidTgts$ Creature | AILogic$ Pump
|
||||
T:Mode$ AttackerBlockedByCreature | ValidCard$ Creature.EnchantedBy | ValidBlocker$ Creature.toughnessLE3 | Execute$ DelTrigBlocker | TriggerZones$ Battlefield | TriggerDescription$ Whenever enchanted creature blocks or becomes blocked by a creature with toughness 3 or less, destroy the other creature at end of combat. At the beginning of the next end step, if that creature was destroyed this way, put a +1/+1 counter on the first creature.
|
||||
T:Mode$ AttackerBlockedByCreature | ValidCard$ Creature.toughnessLE3 | ValidBlocker$ Creature.EnchantedBy | Execute$ DelTrigBlocked | Secondary$ True | TriggerZones$ Battlefield | TriggerDescription$ Whenever enchanted creature blocks or becomes blocked by a creature with toughness 3 or less, destroy the other creature at end of combat. At the beginning of the next end step, if that creature was destroyed this way, put a +1/+1 counter on the first creature.
|
||||
SVar:DelTrigBlocked:DB$ DelayedTrigger | Mode$ Phase | Phase$ EndCombat | ValidPlayer$ Player | Execute$ TrigDestroyBlocked | CopyTriggeringObjects$ True | TriggerDescription$ Destroy blocked creature at end of combat.
|
||||
SVar:DelTrigBlocker:DB$ DelayedTrigger | Mode$ Phase | Phase$ EndCombat | ValidPlayer$ Player | Execute$ TrigDestroyBlocker | CopyTriggeringObjects$ True | TriggerDescription$ Destroy blocking creature at end of combat.
|
||||
SVar:TrigDestroyBlocked:DB$ Destroy | Defined$ TriggeredAttackerLKICopy | RememberDestroyed$ True | SubAbility$ DBDelTrigAttacker
|
||||
SVar:TrigDestroyBlocker:DB$ Destroy | Defined$ TriggeredBlockerLKICopy | RememberDestroyed$ True | SubAbility$ DBDelTrigBlocker
|
||||
SVar:DBDelTrigAttacker:DB$ DelayedTrigger | Mode$ Phase | Phase$ End of Turn | Execute$ DBPutCounter | RememberObjects$ TriggeredBlocker | TriggerDescription$ At the beginning of the next end step, if that creature was destroyed this way, put a +1/+1 counter on the first creature. | ConditionDefined$ Remembered | ConditionPresent$ Card | ConditionCompare$ GE1 | SubAbility$ DBCleanup
|
||||
SVar:DBDelTrigBlocker:DB$ DelayedTrigger | Mode$ Phase | Phase$ End of Turn | Execute$ DBPutCounter | RememberObjects$ TriggeredAttacker | TriggerDescription$ At the beginning of the next end step, if that creature was destroyed this way, put a +1/+1 counter on the first creature. | ConditionDefined$ Remembered | ConditionPresent$ Card | ConditionCompare$ GE1 | SubAbility$ DBCleanup
|
||||
SVar:DelTrigBlocked:DB$ DelayedTrigger | Mode$ Phase | Phase$ EndCombat | ValidPlayer$ Player | Execute$ TrigDestroyBlocked | TriggerDescription$ Destroy blocked creature at end of combat.
|
||||
SVar:DelTrigBlocker:DB$ DelayedTrigger | Mode$ Phase | Phase$ EndCombat | ValidPlayer$ Player | Execute$ TrigDestroyBlocker | TriggerDescription$ Destroy blocking creature at end of combat.
|
||||
SVar:TrigDestroyBlocked:DB$ Destroy | Defined$ Spawner>TriggeredAttackerLKICopy | RememberDestroyed$ True | SubAbility$ DBDelTrigAttacker
|
||||
SVar:TrigDestroyBlocker:DB$ Destroy | Defined$ Spawner>TriggeredBlockerLKICopy | RememberDestroyed$ True | SubAbility$ DBDelTrigBlocker
|
||||
SVar:DBDelTrigAttacker:DB$ DelayedTrigger | Mode$ Phase | Phase$ End of Turn | Execute$ DBPutCounter | RememberObjects$ Spawner>TriggeredBlocker | TriggerDescription$ At the beginning of the next end step, if that creature was destroyed this way, put a +1/+1 counter on the first creature. | ConditionDefined$ Remembered | ConditionPresent$ Card | ConditionCompare$ GE1 | SubAbility$ DBCleanup
|
||||
SVar:DBDelTrigBlocker:DB$ DelayedTrigger | Mode$ Phase | Phase$ End of Turn | Execute$ DBPutCounter | RememberObjects$ Spawner>TriggeredAttacker | TriggerDescription$ At the beginning of the next end step, if that creature was destroyed this way, put a +1/+1 counter on the first creature. | ConditionDefined$ Remembered | ConditionPresent$ Card | ConditionCompare$ GE1 | SubAbility$ DBCleanup
|
||||
SVar:DBPutCounter:DB$ PutCounter | Defined$ DelayTriggerRemembered | CounterType$ P1P1 | CounterNum$ 1
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
DeckHas:Ability$Counters
|
||||
|
||||
@@ -5,6 +5,6 @@ PT:1/3
|
||||
K:Ninjutsu:1 G
|
||||
K:etbCounter:Deathtouch:1
|
||||
T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | Execute$ TrigImmediateTrig | CombatDamage$ True | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, you may remove a deathtouch counter from it. When you do, exile target artifact or enchantment that player controls.
|
||||
SVar:TrigImmediateTrig:AB$ ImmediateTrigger | Cost$ SubCounter<1/Deathtouch> | Execute$ TrigExile | CopyTriggeringObjects$ True | TriggerDescription$ When you do, exile target artifact or enchantment that player controls.
|
||||
SVar:TrigExile:DB$ ChangeZone | ValidTgts$ Artifact.ControlledBy TriggeredTarget,Enchantment.ControlledBy TriggeredTarget | TgtPrompt$ Select target artifact or enchantment creature that player controls | Origin$ Battlefield | Destination$ Exile
|
||||
SVar:TrigImmediateTrig:AB$ ImmediateTrigger | Cost$ SubCounter<1/Deathtouch> | Execute$ TrigExile | TriggerDescription$ When you do, exile target artifact or enchantment that player controls.
|
||||
SVar:TrigExile:DB$ ChangeZone | ValidTgts$ Artifact.ControlledBy Spawner>TriggeredTarget,Enchantment.ControlledBy Spawner>TriggeredTarget | TgtPrompt$ Select target artifact or enchantment creature that player controls | Origin$ Battlefield | Destination$ Exile
|
||||
Oracle:Ninjutsu {1}{G}\nKappa Tech-Wrecker enters the battlefield with a deathtouch counter on it.\nWhenever Kappa Tech-Wrecker deals combat damage to a player, you may remove a deathtouch counter from it. When you do, exile target artifact or enchantment that player controls.
|
||||
|
||||
@@ -4,8 +4,8 @@ Types:Creature Human Ninja
|
||||
PT:2/1
|
||||
K:Ninjutsu:1 B
|
||||
T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | Execute$ TrigImmediateTrig | CombatDamage$ True | OptionalDecider$ You | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, you may discard a card. When you do, destroy target creature or planeswalker that player controls.
|
||||
SVar:TrigImmediateTrig:AB$ ImmediateTrigger | Cost$ Discard<1/Card> | Execute$ TrigDestroy | CopyTriggeringObjects$ True | TriggerDescription$ When you do, destroy target creature or planeswalker that player controls.
|
||||
SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Creature.ControlledBy TriggeredTarget,Planeswalker.ControlledBy TriggeredTarget | TgtPrompt$ Select target creature or planeswalker damaged player controls
|
||||
SVar:TrigImmediateTrig:AB$ ImmediateTrigger | Cost$ Discard<1/Card> | Execute$ TrigDestroy | TriggerDescription$ When you do, destroy target creature or planeswalker that player controls.
|
||||
SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Creature.ControlledBy Spawner>TriggeredTarget,Planeswalker.ControlledBy Spawner>TriggeredTarget | TgtPrompt$ Select target creature or planeswalker damaged player controls
|
||||
DeckHas:Ability$Discard
|
||||
SVar:AIPreference:DiscardCost$Card.cmcLE3
|
||||
Oracle:Ninjutsu {1}{B}\nWhenever Dokuchi Silencer deals combat damage to a player, you may discard a card. When you do, destroy target creature or planeswalker that player controls.
|
||||
|
||||
Reference in New Issue
Block a user