Merge branch 'delayedTriggerX' into 'master'

DelayedTriggerEffect: make the trigger remember the spawning Ability

See merge request core-developers/forge!3427
This commit is contained in:
Michael Kamensky
2020-11-23 04:39:00 +00:00
12 changed files with 53 additions and 38 deletions

View File

@@ -719,7 +719,7 @@ public class Game {
getNextPlayerAfter(p).initPlane();
}
if (p != null && p.equals(getMonarch())) {
if (p != null && p.isMonarch()) {
// if the player who lost was the Monarch, someone else will be the monarch
if(p.equals(getPhaseHandler().getPlayerTurn())) {
getAction().becomeMonarch(getNextPlayerAfter(p));

View File

@@ -1642,6 +1642,12 @@ public class AbilityUtils {
return CardFactoryUtil.doXMath(0, expr, c);
}
// ImmediateTrigger should check for the Ability which created the trigger
if (t.getSpawningAbility() != null) {
root = t.getSpawningAbility().getRootAbility();
return CardFactoryUtil.doXMath(root.getXManaCostPaid(), expr, c);
}
// 107.3k If an objects enters-the-battlefield triggered ability or replacement effect refers to X,
// and the spell that became that object as it resolved had a value of X chosen for any of its costs,
// the value of X for that ability is the same as the value of X for that spell, although the value of X for that permanent is 0.

View File

@@ -58,6 +58,7 @@ public class DelayedTriggerEffect extends SpellAbilityEffect {
Card lki = CardUtil.getLKICopy(gameCard);
lki.setOwner(sa.getActivatingPlayer());
final Trigger delTrig = TriggerHandler.parseTrigger(mapParams, lki, sa.isIntrinsic());
delTrig.setSpawningAbility(sa.copy(lki, sa.getActivatingPlayer(), true));
if (triggerRemembered != null) {
for (final String rem : triggerRemembered.split(",")) {

View File

@@ -57,6 +57,7 @@ public class ImmediateTriggerEffect extends SpellAbilityEffect {
Card lki = CardUtil.getLKICopy(gameCard);
lki.setOwner(sa.getActivatingPlayer());
final Trigger immediateTrig = TriggerHandler.parseTrigger(mapParams, lki, sa.isIntrinsic());
immediateTrig.setSpawningAbility(sa.copy(lki, sa.getActivatingPlayer(), true));
// Need to copy paid costs
@@ -72,11 +73,6 @@ public class ImmediateTriggerEffect extends SpellAbilityEffect {
}
}
if (sa.hasParam("RememberDefinedNumber")) {
immediateTrig.addRemembered((Integer) AbilityUtils.calculateAmount(sa.getHostCard(),
sa.getParam("RememberDefinedNumber"), sa));
}
if (mapParams.containsKey("Execute") || sa.hasAdditionalAbility("Execute")) {
AbilitySub overridingSA = (AbilitySub)sa.getAdditionalAbility("Execute").copy(lki, sa.getActivatingPlayer(), false);
// need to set Parent to null, otherwise it might have wrong root ability

View File

@@ -1167,7 +1167,7 @@ public class CardFactoryUtil {
return doXMath(Integer.parseInt(sq[cc.hasLandfall() ? 1 : 2]), m, c);
}
if (sq[0].contains("Monarch")) {
return doXMath(Integer.parseInt(sq[cc.equals(game.getMonarch()) ? 1 : 2]), m, c);
return doXMath(Integer.parseInt(sq[cc.isMonarch() ? 1 : 2]), m, c);
}
if (sq[0].contains("Blessing")) {
return doXMath(Integer.parseInt(sq[cc.hasBlessing() ? 1 : 2]), m, c);

View File

@@ -3113,6 +3113,10 @@ public class Player extends GameEntity implements Comparable<Player> {
return view;
}
public boolean isMonarch() {
return equals(game.getMonarch());
}
public void createMonarchEffect() {
final PlayerZone com = getZone(ZoneType.Command);
if (monarchEffect == null) {

View File

@@ -70,7 +70,11 @@ public class PlayerProperty {
return false;
}
} else if (property.equals("isMonarch")) {
if (!player.equals(game.getMonarch())) {
if (!player.isMonarch()) {
return false;
}
} else if (property.equals("isNotMonarch")) {
if (player.isMonarch()) {
return false;
}
} else if (property.equals("hasBlessing")) {

View File

@@ -6,12 +6,12 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
@@ -44,7 +44,7 @@ import forge.util.TextUtil;
* <p>
* Abstract Trigger class. Constructed by reflection only
* </p>
*
*
* @author Forge
* @version $Id$
*/
@@ -74,11 +74,13 @@ public abstract class Trigger extends TriggerReplacementBase {
private Set<PhaseType> validPhases;
private SpellAbility spawningAbility = null;
/**
* <p>
* Constructor for Trigger.
* </p>
*
*
* @param params
* a {@link java.util.HashMap} object.
* @param host
@@ -109,14 +111,14 @@ public abstract class Trigger extends TriggerReplacementBase {
* <p>
* toString.
* </p>
*
*
* @return a {@link java.lang.String} object.
*/
@Override
public final String toString() {
return toString(false);
}
public String toString(boolean active) {
if (hasParam("TriggerDescription") && !this.isSuppressed()) {
@@ -148,9 +150,9 @@ public abstract class Trigger extends TriggerReplacementBase {
SpellAbility sa = ensureAbility();
return replaceAbilityText(desc, sa);
}
public final String replaceAbilityText(final String desc, SpellAbility sa) {
String result = desc;
@@ -204,7 +206,7 @@ public abstract class Trigger extends TriggerReplacementBase {
* <p>
* phasesCheck.
* </p>
*
*
* @return a boolean.
*/
public final boolean phasesCheck(final Game game) {
@@ -270,7 +272,7 @@ public abstract class Trigger extends TriggerReplacementBase {
* <p>
* requirementsCheck.
* </p>
* @param game
* @param game
*
* @return a boolean.
*/
@@ -398,7 +400,7 @@ public abstract class Trigger extends TriggerReplacementBase {
* <p>
* performTest.
* </p>
*
*
* @param runParams
* a {@link HashMap} object.
* @return a boolean.
@@ -409,7 +411,7 @@ public abstract class Trigger extends TriggerReplacementBase {
* <p>
* setTriggeringObjects.
* </p>
*
*
* @param sa
* a {@link forge.game.spellability.SpellAbility} object.
*/
@@ -439,7 +441,7 @@ public abstract class Trigger extends TriggerReplacementBase {
public void addRemembered(Object o) {
this.triggerRemembered.add(o);
}
public List<Object> getTriggerRemembered() {
return this.triggerRemembered;
}
@@ -453,7 +455,7 @@ public abstract class Trigger extends TriggerReplacementBase {
}
/**
*
*
* @param triggerType
* the triggerType to set
* @param triggerType
@@ -493,6 +495,14 @@ public abstract class Trigger extends TriggerReplacementBase {
//public String getImportantStackObjects(SpellAbility sa) { return ""; };
abstract public String getImportantStackObjects(SpellAbility sa);
public SpellAbility getSpawningAbility() {
return spawningAbility;
}
public void setSpawningAbility(SpellAbility ability) {
spawningAbility = ability;
}
public int getActivationsThisTurn() {
return this.numberTurnActivations;
}

View File

@@ -4,11 +4,8 @@ Types:Legendary Creature Human Wizard
K:Deathtouch
PT:3/3
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigImmediateTrig | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME attacks, you may pay {X}. When you do, return target creature card with converted mana cost X from your graveyard to the battlefield with a corpse counter on it. If that creature would leave the battlefield, exile it instead of putting it anywhere else.
SVar:TrigImmediateTrig:AB$ ImmediateTrigger | Cost$ X | Execute$ TrigChange | RememberDefinedNumber$ X | References$ X | TriggerDescription$ When you do, return target creature card with converted mana cost X from your graveyard to the battlefield with a corpse counter on it. If that creature would leave the battlefield, exile it instead of putting it anywhere else.
SVar:TrigImmediateTrig:AB$ ImmediateTrigger | Cost$ X | Execute$ TrigChange | References$ X | SpellDescription$ When you do, return target creature card with converted mana cost X from your graveyard to the battlefield with a corpse counter on it. If that creature would leave the battlefield, exile it instead of putting it anywhere else.
SVar:X:Count$xPaid
SVar:TrigChange:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ValidTgts$ Creature.YouOwn+cmcEQY | TgtPrompt$ Choose target creature card with converted mana cost X | References$ Y | RememberTargets$ True | AILogic$ BeforeCombat | SubAbility$ DBPutCounter | SpellDescription$ Return target creature card with converted mana cost X from your graveyard to the battlefield.
SVar:DBPutCounter:DB$ PutCounter | Defined$ Targeted | CounterType$ CORPSE | CounterNum$ 1 | SubAbility$ DBPump
SVar:DBPump:DB$ Pump | Defined$ Remembered | LeaveBattlefield$ Exile
SVar:Y:Count$TriggerRememberAmount
SVar:TrigChange:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ValidTgts$ Creature.YouOwn+cmcEQX | TgtPrompt$ Choose target creature card with converted mana cost X | References$ X | WithCounters$ CORPSE_1 | AILogic$ BeforeCombat | LeaveBattlefield$ Exile | SpellDescription$ Return target creature card with converted mana cost X from your graveyard to the battlefield.
SVar:HasAttackEffect:TRUE
Oracle:Deathtouch\nWhenever Isareth the Awakener attacks, you may pay {X}. When you do, return target creature card with converted mana cost X from your graveyard to the battlefield with a corpse counter on it. If that creature would leave the battlefield, exile it instead of putting it anywhere else.
Oracle:Deathtouch\nWhenever Isareth the Awakener attacks, you may pay {X}. When you do, return target creature card with converted mana cost X from your graveyard to the battlefield with a corpse counter on it. If that creature would leave the battlefield, exile it instead of putting it anywhere else.

View File

@@ -5,9 +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 | RememberObjects$ TriggeredCard | SubAbility$ DBCleanup | TriggerDescription$ When you pay {2}, that creature deals damage equal to its power to target creature.
SVar:TrigDealDamage:DB$ DealDamage | DamageSource$ DelayTriggerRememberedLKI | NumDmg$ XPower | References$ XPower | ValidTgts$ Creature
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:XPower:TriggerRememberedLKI$CardPower
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 | References$ X | ValidTgts$ Creature
SVar:X: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.)

View File

@@ -3,10 +3,9 @@ ManaCost:2 G
Types:Legendary Creature Elf Warrior
PT:2/2
T:Mode$ Phase | Phase$ BeginCombat | ValidPlayer$ You | Execute$ TrigPayCost | TriggerZones$ Battlefield | TriggerDescription$ At the beginning of combat on your turn, you may pay {X}{X}. When you do, distribute X +1/+1 counters among any number of target Elf creatures you control.
SVar:TrigPayCost:AB$ ImmediateTrigger | Cost$ X X | RememberDefinedNumber$ X | References$ X | Execute$ TrigPutCounters | TriggerDescription$ When you pay {X}{X}, distribute X +1/+1 counters among any number of target Elf creatures you control.
SVar:TrigPutCounters:DB$ PutCounter | ValidTgts$ Creature.Elf+YouCtrl | TgtPrompt$ Select any number of target Elf creatures you control to distribute counters to | CounterType$ P1P1 | CounterNum$ Y | TargetMin$ 1 | TargetMax$ Y | DividedAsYouChoose$ Y | References$ Y
SVar:TrigPayCost:AB$ ImmediateTrigger | Cost$ X X | References$ X | Execute$ TrigPutCounters | TriggerDescription$ When you pay {X}{X}, distribute X +1/+1 counters among any number of target Elf creatures you control.
SVar:TrigPutCounters:DB$ PutCounter | ValidTgts$ Creature.Elf+YouCtrl | TgtPrompt$ Select any number of target Elf creatures you control to distribute counters to | CounterType$ P1P1 | CounterNum$ Y | TargetMin$ 1 | TargetMax$ X | DividedAsYouChoose$ X | References$ X
SVar:X:Count$xPaid
SVar:Y:Count$TriggerRememberAmount
K:Partner
DeckHas:Ability$Counters
DeckHints:Type$Elf

View File

@@ -5,9 +5,8 @@ PT:2/2
K:Flash
K:Reach
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.nonHuman+Other+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigImmediateTrig | TriggerDescription$ Whenever another non-Human creature enters the battlefield under your control, you may pay {X}. When you do, put X +1/+1 counters on CARDNAME.
SVar:TrigImmediateTrig:AB$ ImmediateTrigger | Cost$ X | Execute$ TrigPutCounter | RememberDefinedNumber$ X | References$ X | TriggerDescription$ When you do, put X +1/+1 counters on CARDNAME.
SVar:TrigImmediateTrig:AB$ ImmediateTrigger | Cost$ X | Execute$ TrigPutCounter | References$ X | TriggerDescription$ When you do, put X +1/+1 counters on CARDNAME.
SVar:X:Count$xPaid
SVar:TrigPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ Y | References$ Y
SVar:Y:Count$TriggerRememberAmount
SVar:TrigPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ X | References$ X
DeckHas:Ability$Counters
Oracle:Flash\nReach\nWhenever another non-Human creature enters the battlefield under your control, you may pay {X}. When you do, put X +1/+1 counters on Wildborn Preserver.