mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-20 12:48:00 +00:00
Trigger & Replacement: ensure abilities
This commit is contained in:
@@ -249,7 +249,7 @@ public final class AbilityFactory {
|
||||
}
|
||||
}
|
||||
|
||||
if (api == ApiType.DelayedTrigger && mapParams.containsKey("Execute")) {
|
||||
if ((api == ApiType.DelayedTrigger || api == ApiType.ImmediateTrigger) && mapParams.containsKey("Execute")) {
|
||||
spellAbility.setSVar(mapParams.get("Execute"), sVarHolder.getSVar(mapParams.get("Execute")));
|
||||
}
|
||||
|
||||
|
||||
@@ -429,7 +429,7 @@ public abstract class SpellAbilityEffect {
|
||||
+ " exile it instead of putting it anywhere else.";
|
||||
String effect = "DB$ ChangeZone | Defined$ ReplacedCard | Origin$ Battlefield | Destination$ " + zone;
|
||||
|
||||
ReplacementEffect re = ReplacementHandler.parseReplacement(repeffstr, eff, true);
|
||||
ReplacementEffect re = ReplacementHandler.parseReplacement(repeffstr, eff, true, null);
|
||||
re.setLayer(ReplacementLayer.Other);
|
||||
|
||||
re.setOverridingAbility(AbilityFactory.getAbility(effect, eff));
|
||||
|
||||
@@ -159,8 +159,7 @@ public abstract class AnimateEffectBase extends SpellAbilityEffect {
|
||||
// Grant triggers
|
||||
final List<Trigger> addedTriggers = Lists.newArrayList();
|
||||
for (final String s : triggers) {
|
||||
final Trigger parsedTrigger = TriggerHandler.parseTrigger(AbilityUtils.getSVar(sa, s), c, false);
|
||||
parsedTrigger.setOverridingAbility(AbilityFactory.getAbility(c, parsedTrigger.getParam("Execute"), sa));
|
||||
final Trigger parsedTrigger = TriggerHandler.parseTrigger(AbilityUtils.getSVar(sa, s), c, false, sa);
|
||||
parsedTrigger.setOriginalHost(source);
|
||||
addedTriggers.add(parsedTrigger);
|
||||
}
|
||||
@@ -168,7 +167,7 @@ public abstract class AnimateEffectBase extends SpellAbilityEffect {
|
||||
// give replacement effects
|
||||
final List<ReplacementEffect> addedReplacements = Lists.newArrayList();
|
||||
for (final String s : replacements) {
|
||||
addedReplacements.add(ReplacementHandler.parseReplacement(AbilityUtils.getSVar(sa, s), c, false));
|
||||
addedReplacements.add(ReplacementHandler.parseReplacement(AbilityUtils.getSVar(sa, s), c, false, sa));
|
||||
}
|
||||
|
||||
// give static abilities (should only be used by cards to give
|
||||
|
||||
@@ -58,7 +58,7 @@ public class DelayedTriggerEffect extends SpellAbilityEffect {
|
||||
Card lki = CardUtil.getLKICopy(gameCard);
|
||||
lki.clearControllers();
|
||||
lki.setOwner(sa.getActivatingPlayer());
|
||||
final Trigger delTrig = TriggerHandler.parseTrigger(mapParams, lki, sa.isIntrinsic());
|
||||
final Trigger delTrig = TriggerHandler.parseTrigger(mapParams, lki, sa.isIntrinsic(), null);
|
||||
delTrig.setSpawningAbility(sa.copy(lki, sa.getActivatingPlayer(), true));
|
||||
|
||||
if (triggerRemembered != null) {
|
||||
@@ -81,7 +81,7 @@ public class DelayedTriggerEffect extends SpellAbilityEffect {
|
||||
}
|
||||
}
|
||||
|
||||
if (mapParams.containsKey("Execute") || sa.hasAdditionalAbility("Execute")) {
|
||||
if (sa.hasAdditionalAbility("Execute")) {
|
||||
AbilitySub overridingSA = (AbilitySub)sa.getAdditionalAbility("Execute").copy(lki, sa.getActivatingPlayer(), false);
|
||||
// need to reset the parent, additionalAbility does set it to this
|
||||
overridingSA.setParent(null);
|
||||
@@ -96,7 +96,7 @@ public class DelayedTriggerEffect extends SpellAbilityEffect {
|
||||
|
||||
delTrig.setOverridingAbility(overridingSA);
|
||||
}
|
||||
final TriggerHandler trigHandler = sa.getActivatingPlayer().getGame().getTriggerHandler();
|
||||
final TriggerHandler trigHandler = game.getTriggerHandler();
|
||||
if (mapParams.containsKey("DelayedTriggerDefinedPlayer")) { // on sb's next turn
|
||||
Player p = Iterables.getFirst(AbilityUtils.getDefinedPlayers(sa.getHostCard(), mapParams.get("DelayedTriggerDefinedPlayer"), sa), null);
|
||||
trigHandler.registerPlayerDefinedDelayedTrigger(p, delTrig);
|
||||
|
||||
@@ -189,7 +189,7 @@ public class EffectEffect extends SpellAbilityEffect {
|
||||
for (final String s : effectReplacementEffects) {
|
||||
final String actualReplacement = AbilityUtils.getSVar(sa, s);
|
||||
|
||||
final ReplacementEffect parsedReplacement = ReplacementHandler.parseReplacement(actualReplacement, eff, true);
|
||||
final ReplacementEffect parsedReplacement = ReplacementHandler.parseReplacement(actualReplacement, eff, true, sa);
|
||||
parsedReplacement.setActiveZone(EnumSet.of(ZoneType.Command));
|
||||
parsedReplacement.setIntrinsic(true);
|
||||
eff.addReplacementEffect(parsedReplacement);
|
||||
|
||||
@@ -57,7 +57,7 @@ public class ImmediateTriggerEffect extends SpellAbilityEffect {
|
||||
Card lki = CardUtil.getLKICopy(gameCard);
|
||||
lki.clearControllers();
|
||||
lki.setOwner(sa.getActivatingPlayer());
|
||||
final Trigger immediateTrig = TriggerHandler.parseTrigger(mapParams, lki, sa.isIntrinsic());
|
||||
final Trigger immediateTrig = TriggerHandler.parseTrigger(mapParams, lki, sa.isIntrinsic(), null);
|
||||
immediateTrig.setSpawningAbility(sa.copy(lki, sa.getActivatingPlayer(), true));
|
||||
|
||||
// Need to copy paid costs
|
||||
@@ -74,7 +74,7 @@ public class ImmediateTriggerEffect extends SpellAbilityEffect {
|
||||
}
|
||||
}
|
||||
|
||||
if (mapParams.containsKey("Execute") || sa.hasAdditionalAbility("Execute")) {
|
||||
if (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
|
||||
overridingSA.setParent(null);
|
||||
@@ -85,9 +85,8 @@ public class ImmediateTriggerEffect extends SpellAbilityEffect {
|
||||
|
||||
immediateTrig.setOverridingAbility(overridingSA);
|
||||
}
|
||||
final TriggerHandler trigHandler = sa.getActivatingPlayer().getGame().getTriggerHandler();
|
||||
|
||||
// Instead of registering this, add to the delayed triggers as an immediate trigger type? Which means it'll fire as soon as possible
|
||||
trigHandler.registerDelayedTrigger(immediateTrig);
|
||||
game.getTriggerHandler().registerDelayedTrigger(immediateTrig);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5932,21 +5932,20 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
|
||||
public boolean hasETBTrigger(final boolean drawbackOnly) {
|
||||
for (final Trigger tr : getTriggers()) {
|
||||
final Map<String, String> params = tr.getMapParams();
|
||||
if (tr.getMode() != TriggerType.ChangesZone) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!params.get("Destination").equals(ZoneType.Battlefield.toString())) {
|
||||
if (!tr.getParam("Destination").equals(ZoneType.Battlefield.toString())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (params.containsKey("ValidCard") && !params.get("ValidCard").contains("Self")) {
|
||||
if (tr.hasParam("ValidCard") && !tr.getParam("ValidCard").contains("Self")) {
|
||||
continue;
|
||||
}
|
||||
if (drawbackOnly && params.containsKey("Execute")){
|
||||
String exec = this.getSVar(params.get("Execute"));
|
||||
if (exec.contains("AB$")) {
|
||||
if (drawbackOnly) {
|
||||
SpellAbility sa = tr.ensureAbility();
|
||||
if (sa == null || sa.isActivatedAbility()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -664,6 +664,7 @@ public class CardFactory {
|
||||
if (origSVars.containsKey(s)) {
|
||||
final String actualTrigger = origSVars.get(s);
|
||||
final Trigger parsedTrigger = TriggerHandler.parseTrigger(actualTrigger, out, true);
|
||||
parsedTrigger.setOriginalHost(host);
|
||||
state.addTrigger(parsedTrigger);
|
||||
}
|
||||
}
|
||||
@@ -687,6 +688,7 @@ public class CardFactory {
|
||||
if (origSVars.containsKey(s)) {
|
||||
final String actualAbility = origSVars.get(s);
|
||||
final SpellAbility grantedAbility = AbilityFactory.getAbility(actualAbility, out);
|
||||
grantedAbility.setOriginalHost(host);
|
||||
grantedAbility.setIntrinsic(true);
|
||||
state.addSpellAbility(grantedAbility);
|
||||
}
|
||||
@@ -700,6 +702,7 @@ public class CardFactory {
|
||||
if (origSVars.containsKey(s)) {
|
||||
final String actualStatic = origSVars.get(s);
|
||||
final StaticAbility grantedStatic = new StaticAbility(actualStatic, out);
|
||||
grantedStatic.setOriginalHost(host);
|
||||
grantedStatic.setIntrinsic(true);
|
||||
state.addStaticAbility(grantedStatic);
|
||||
}
|
||||
|
||||
@@ -2227,7 +2227,7 @@ public class CardFactoryUtil {
|
||||
final String abStringAfflict = "DB$ LoseLife | Defined$ TriggeredDefendingPlayer" +
|
||||
" | LifeAmount$ " + n;
|
||||
|
||||
final Trigger afflictTrigger = TriggerHandler.parseTrigger(trigStr, card, intrinsic);
|
||||
final Trigger afflictTrigger = TriggerHandler.parseTrigger(trigStr, card, intrinsic, null);
|
||||
afflictTrigger.setOverridingAbility(AbilityFactory.getAbility(abStringAfflict, card));
|
||||
|
||||
inst.addTrigger(afflictTrigger);
|
||||
|
||||
@@ -19,6 +19,7 @@ package forge.game.replacement;
|
||||
|
||||
import forge.game.Game;
|
||||
import forge.game.GameLogEntryType;
|
||||
import forge.game.IHasSVars;
|
||||
import forge.game.ability.AbilityFactory;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
@@ -370,7 +371,10 @@ public class ReplacementHandler {
|
||||
* @return A finished instance
|
||||
*/
|
||||
public static ReplacementEffect parseReplacement(final String repParse, final Card host, final boolean intrinsic) {
|
||||
return ReplacementHandler.parseReplacement(parseParams(repParse), host, intrinsic);
|
||||
return parseReplacement(repParse, host, intrinsic, host);
|
||||
}
|
||||
public static ReplacementEffect parseReplacement(final String repParse, final Card host, final boolean intrinsic, final IHasSVars sVarHolder) {
|
||||
return ReplacementHandler.parseReplacement(parseParams(repParse), host, intrinsic, sVarHolder);
|
||||
}
|
||||
|
||||
public static Map<String, String> parseParams(final String repParse) {
|
||||
@@ -388,7 +392,7 @@ public class ReplacementHandler {
|
||||
* The card that hosts the replacement effect
|
||||
* @return The finished instance
|
||||
*/
|
||||
private static ReplacementEffect parseReplacement(final Map<String, String> mapParams, final Card host, final boolean intrinsic) {
|
||||
private static ReplacementEffect parseReplacement(final Map<String, String> mapParams, final Card host, final boolean intrinsic, final IHasSVars sVarHolder) {
|
||||
final ReplacementType rt = ReplacementType.smartValueOf(mapParams.get("Event"));
|
||||
ReplacementEffect ret = rt.createReplacement(mapParams, host, intrinsic);
|
||||
|
||||
@@ -397,8 +401,8 @@ public class ReplacementHandler {
|
||||
ret.setActiveZone(EnumSet.copyOf(ZoneType.listValueOf(activeZones)));
|
||||
}
|
||||
|
||||
if (mapParams.containsKey("ReplaceWith")) {
|
||||
ret.setOverridingAbility(AbilityFactory.getAbility(host, mapParams.get("ReplaceWith"), ret));
|
||||
if (mapParams.containsKey("ReplaceWith") && sVarHolder != null) {
|
||||
ret.setOverridingAbility(AbilityFactory.getAbility(host, mapParams.get("ReplaceWith"), sVarHolder));
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -781,8 +781,7 @@ public final class StaticAbilityContinuous {
|
||||
// add Replacement effects
|
||||
if (addReplacements != null) {
|
||||
for (String rep : addReplacements) {
|
||||
final ReplacementEffect actualRep = ReplacementHandler.parseReplacement(rep, affectedCard, false);
|
||||
actualRep.setIntrinsic(false);
|
||||
final ReplacementEffect actualRep = ReplacementHandler.parseReplacement(rep, affectedCard, false, stAb);
|
||||
addedReplacementEffects.add(actualRep);
|
||||
}
|
||||
}
|
||||
@@ -790,17 +789,12 @@ public final class StaticAbilityContinuous {
|
||||
// add triggers
|
||||
if (addTriggers != null) {
|
||||
for (final String trigger : addTriggers) {
|
||||
final Trigger actualTrigger = TriggerHandler.parseTrigger(trigger, affectedCard, false);
|
||||
final Trigger actualTrigger = TriggerHandler.parseTrigger(trigger, affectedCard, false, stAb);
|
||||
// if the trigger has Execute param, which most trigger gained by Static Abilties should have
|
||||
// turn them into SpellAbility object before adding to card
|
||||
// with that the TargetedCard does not need the Svars added to them anymore
|
||||
// but only do it if the trigger doesn't already have a overriding ability
|
||||
if (actualTrigger.hasParam("Execute") && actualTrigger.getOverridingAbility() == null) {
|
||||
// set overriding ability to the trigger
|
||||
actualTrigger.setOverridingAbility(AbilityFactory.getAbility(affectedCard, actualTrigger.getParam("Execute"), stAb));
|
||||
}
|
||||
actualTrigger.setOriginalHost(hostCard);
|
||||
actualTrigger.setIntrinsic(false);
|
||||
addedTrigger.add(actualTrigger);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package forge.game.trigger;
|
||||
|
||||
import forge.game.Game;
|
||||
import forge.game.GameEntity;
|
||||
import forge.game.IHasSVars;
|
||||
import forge.game.TriggerReplacementBase;
|
||||
import forge.game.ability.AbilityFactory;
|
||||
import forge.game.ability.AbilityKey;
|
||||
@@ -562,12 +563,16 @@ public abstract class Trigger extends TriggerReplacementBase {
|
||||
}
|
||||
}
|
||||
|
||||
public SpellAbility ensureAbility() {
|
||||
public SpellAbility ensureAbility(final IHasSVars sVarHolder) {
|
||||
SpellAbility sa = getOverridingAbility();
|
||||
if (sa == null && hasParam("Execute")) {
|
||||
sa = AbilityFactory.getAbility(getHostCard(), getParam("Execute"));
|
||||
sa = AbilityFactory.getAbility(getHostCard(), getParam("Execute"), sVarHolder);
|
||||
setOverridingAbility(sa);
|
||||
}
|
||||
return sa;
|
||||
}
|
||||
|
||||
public SpellAbility ensureAbility() {
|
||||
return ensureAbility(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package forge.game.trigger;
|
||||
|
||||
import forge.game.Game;
|
||||
import forge.game.GlobalRuleChange;
|
||||
import forge.game.IHasSVars;
|
||||
import forge.game.ability.AbilityFactory;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.ApiType;
|
||||
@@ -123,9 +124,13 @@ public class TriggerHandler {
|
||||
}
|
||||
|
||||
public static Trigger parseTrigger(final String trigParse, final Card host, final boolean intrinsic) {
|
||||
return parseTrigger(trigParse, host, intrinsic, host);
|
||||
}
|
||||
|
||||
public static Trigger parseTrigger(final String trigParse, final Card host, final boolean intrinsic, final IHasSVars sVarHolder) {
|
||||
try {
|
||||
final Map<String, String> mapParams = TriggerHandler.parseParams(trigParse);
|
||||
return TriggerHandler.parseTrigger(mapParams, host, intrinsic);
|
||||
return TriggerHandler.parseTrigger(mapParams, host, intrinsic, sVarHolder);
|
||||
} catch (Exception e) {
|
||||
String msg = "TriggerHandler:parseTrigger failed to parse";
|
||||
Sentry.getContext().recordBreadcrumb(
|
||||
@@ -137,12 +142,15 @@ public class TriggerHandler {
|
||||
}
|
||||
}
|
||||
|
||||
public static Trigger parseTrigger(final Map<String, String> mapParams, final Card host, final boolean intrinsic) {
|
||||
public static Trigger parseTrigger(final Map<String, String> mapParams, final Card host, final boolean intrinsic, final IHasSVars sVarHolder) {
|
||||
Trigger ret = null;
|
||||
|
||||
try {
|
||||
final TriggerType type = TriggerType.smartValueOf(mapParams.get("Mode"));
|
||||
ret = type.createTrigger(mapParams, host, intrinsic);
|
||||
if (sVarHolder != null) {
|
||||
ret.ensureAbility(sVarHolder);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
String msg = "TriggerHandler:parseTrigger failed to parse";
|
||||
Sentry.getContext().recordBreadcrumb(
|
||||
|
||||
Reference in New Issue
Block a user