...
 
Commits (10)
......@@ -1266,7 +1266,7 @@ public class ComputerUtil {
public static boolean preventRunAwayActivations(final SpellAbility sa) {
int activations = sa.getActivationsThisTurn();
if (sa.isTemporary()) {
if (!sa.isIntrinsic()) {
return MyRandom.getRandom().nextFloat() >= .95; // Abilities created by static abilities have no memory
}
......
......@@ -1128,14 +1128,14 @@ public class ComputerUtilCard {
// assume it either benefits the player or disrupts the opponent
for (final StaticAbility stAb : c.getStaticAbilities()) {
final Map<String, String> params = stAb.getMapParams();
if (params.get("Mode").equals("Continuous") && stAb.isIntrinsic() && !stAb.isTemporary()) {
if (params.get("Mode").equals("Continuous") && stAb.isIntrinsic()) {
priority = true;
break;
}
}
if (!priority) {
for (final Trigger t : c.getTriggers()) {
if (t.isIntrinsic() && !t.isTemporary()) {
if (t.isIntrinsic()) {
// has a triggered ability, could be benefitting the opponent or disrupting the AI
priority = true;
break;
......
......@@ -467,26 +467,19 @@ public class AnimateAi extends SpellAbilityAi {
AnimateEffectBase.doAnimate(card, sa, power, toughness, types, removeTypes, finalDesc, keywords, removeKeywords, hiddenKeywords, timestamp);
// back to duplicating AnimateEffect.resolve
// TODO will all these abilities/triggers/replacements/etc. lead to
// memory leaks or unintended effects?
// remove abilities
final List<SpellAbility> removedAbilities = Lists.newArrayList();
boolean clearAbilities = sa.hasParam("OverwriteAbilities");
boolean clearSpells = sa.hasParam("OverwriteSpells");
boolean removeAll = sa.hasParam("RemoveAllAbilities");
boolean removeIntrinsic = sa.hasParam("RemoveIntrinsicAbilities");
if (clearAbilities || clearSpells || removeAll) {
for (final SpellAbility ab : card.getSpellAbilities()) {
if (removeAll
|| (ab.isIntrinsic() && removeIntrinsic && !ab.isBasicLandAbility())
|| (ab.isAbility() && clearAbilities)
|| (ab.isSpell() && clearSpells)) {
card.removeSpellAbility(ab);
removedAbilities.add(ab);
}
}
if (clearSpells) {
removedAbilities.addAll(Lists.newArrayList(card.getSpells()));
}
if (sa.hasParam("RemoveThisAbility") && !removedAbilities.contains(sa)) {
removedAbilities.add(sa);
}
// give abilities
......@@ -494,9 +487,7 @@ public class AnimateAi extends SpellAbilityAi {
if (abilities.size() > 0) {
for (final String s : abilities) {
final String actualAbility = source.getSVar(s);
final SpellAbility grantedAbility = AbilityFactory.getAbility(actualAbility, source);
addedAbilities.add(grantedAbility);
card.addSpellAbility(grantedAbility);
addedAbilities.add(AbilityFactory.getAbility(actualAbility, card));
}
}
......@@ -505,8 +496,8 @@ public class AnimateAi extends SpellAbilityAi {
if (triggers.size() > 0) {
for (final String s : triggers) {
final String actualTrigger = source.getSVar(s);
final Trigger parsedTrigger = TriggerHandler.parseTrigger(actualTrigger, source, false);
addedTriggers.add(card.addTrigger(parsedTrigger));
final Trigger parsedTrigger = TriggerHandler.parseTrigger(actualTrigger, card, false);
addedTriggers.add(parsedTrigger);
}
}
......@@ -515,24 +506,28 @@ public class AnimateAi extends SpellAbilityAi {
if (replacements.size() > 0) {
for (final String s : replacements) {
final String actualReplacement = source.getSVar(s);
final ReplacementEffect parsedReplacement = ReplacementHandler.parseReplacement(actualReplacement,
source, false);
addedReplacements.add(card.addReplacementEffect(parsedReplacement));
final ReplacementEffect parsedReplacement = ReplacementHandler.parseReplacement(actualReplacement, card, false);
addedReplacements.add(parsedReplacement);
}
}
// suppress triggers from the animated card
final List<Trigger> removedTriggers = Lists.newArrayList();
if (sa.hasParam("OverwriteTriggers") || removeAll || removeIntrinsic) {
for (final Trigger trigger : card.getTriggers()) {
if (removeIntrinsic && !trigger.isIntrinsic()) {
continue;
}
trigger.setSuppressed(true);
removedTriggers.add(trigger);
// give static abilities (should only be used by cards to give
// itself a static ability)
final List<StaticAbility> addedStaticAbilities = Lists.newArrayList();
if (stAbs.size() > 0) {
for (final String s : stAbs) {
final String actualAbility = source.getSVar(s);
addedStaticAbilities.add(new StaticAbility(actualAbility, card));
}
}
if (removeAll || removeIntrinsic
|| !addedAbilities.isEmpty() || !removedAbilities.isEmpty() || !addedTriggers.isEmpty()
|| !addedReplacements.isEmpty() || !addedStaticAbilities.isEmpty()) {
card.addChangedCardTraits(addedAbilities, removedAbilities, addedTriggers, addedReplacements,
addedStaticAbilities, removeAll, false, removeIntrinsic, timestamp);
}
// give static abilities (should only be used by cards to give
// itself a static ability)
if (stAbs.size() > 0) {
......@@ -560,30 +555,6 @@ public class AnimateAi extends SpellAbilityAi {
card.setSVar(name, actualsVar);
}
}
// suppress static abilities from the animated card
final List<StaticAbility> removedStatics = Lists.newArrayList();
if (sa.hasParam("OverwriteStatics") || removeAll || removeIntrinsic) {
for (final StaticAbility stAb : card.getStaticAbilities()) {
if (removeIntrinsic && !stAb.isIntrinsic()) {
continue;
}
stAb.setTemporarilySuppressed(true);
removedStatics.add(stAb);
}
}
// suppress static abilities from the animated card
final List<ReplacementEffect> removedReplacements = Lists.newArrayList();
if (sa.hasParam("OverwriteReplacements") || removeAll || removeIntrinsic) {
for (final ReplacementEffect re : card.getReplacementEffects()) {
if (removeIntrinsic && !re.isIntrinsic()) {
continue;
}
re.setTemporarilySuppressed(true);
removedReplacements.add(re);
}
}
ComputerUtilCard.applyStaticContPT(game, card, null);
}
......
......@@ -38,15 +38,9 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView {
/** The is intrinsic. */
protected boolean intrinsic;
/** The temporary. */
protected boolean temporary = false;
/** The suppressed. */
protected boolean suppressed = false;
/** The temporarily suppressed. */
protected boolean temporarilySuppressed = false;
protected Map<String, String> sVars = Maps.newHashMap();
protected Map<String, String> intrinsicChangedTextColors = Maps.newHashMap();
......@@ -66,24 +60,6 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView {
*/
private static final ImmutableList<String> noChangeKeys = ImmutableList.<String>builder()
.add("TokenScript", "LegacyImage", "TokenImage", "NewName").build();
/**
* Sets the temporary.
*
* @param temp
* the new temporary
*/
public final void setTemporary(final boolean temp) {
this.temporary = temp;
}
/**
* Checks if is temporary.
*
* @return true, if is temporary
*/
public final boolean isTemporary() {
return this.temporary;
}
/**
* <p>
......@@ -196,26 +172,12 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView {
this.suppressed = supp;
}
/**
* Sets the temporarily suppressed.
*
* @param supp
* the new temporarily suppressed
*/
public final void setTemporarilySuppressed(final boolean supp) {
this.temporarilySuppressed = supp;
}
/**
* Checks if is suppressed.
*
* @return true, if is suppressed
*/
public final boolean isSuppressed() {
return (this.suppressed || this.temporarilySuppressed);
}
protected final boolean isNonTempSuppressed() {
return this.suppressed;
}
......
......@@ -148,7 +148,7 @@ public class GameAction {
}
// if an adventureCard is put from Stack somewhere else, need to reset to Original State
if (c.isAdventureCard() && (ZoneType.Stack.equals(zoneFrom) || !ZoneType.Stack.equals(zoneTo))) { //fix NPE momir
if (c.isAdventureCard() && ((zoneFrom != null && zoneFrom.is(ZoneType.Stack)) || !zoneTo.is(ZoneType.Stack))) {
c.setState(CardStateName.Original, true);
}
......@@ -760,8 +760,6 @@ public class GameAction {
// remove old effects
game.getStaticEffects().clearStaticEffects(affectedCards);
game.getTriggerHandler().cleanUpTemporaryTriggers();
game.getReplacementHandler().cleanUpTemporaryReplacements();
for (final Player p : game.getPlayers()) {
if (!game.getStack().isFrozen()) {
......@@ -779,17 +777,11 @@ public class GameAction {
public boolean visit(final Card c) {
// need to get Card from preList if able
final Card co = preList.get(c);
List<StaticAbility> toRemove = Lists.newArrayList();
for (StaticAbility stAb : co.getStaticAbilities()) {
if (stAb.isTemporary()) {
toRemove.add(stAb);
} else if (stAb.getParam("Mode").equals("Continuous")) {
if (stAb.getParam("Mode").equals("Continuous")) {
staticAbilities.add(stAb);
}
}
for (StaticAbility stAb : toRemove) {
co.removeStaticAbility(stAb);
}
if (!co.getStaticCommandList().isEmpty()) {
staticList.add(co);
}
......
......@@ -23,8 +23,6 @@ import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardUtil;
import forge.game.player.Player;
import forge.game.spellability.AbilityStatic;
import forge.game.spellability.SpellAbility;
import forge.game.staticability.StaticAbility;
import java.util.ArrayList;
......@@ -236,11 +234,7 @@ public class StaticEffect {
}
if (hasParam("IgnoreEffectCost")) {
for (final SpellAbility s : getSource().getSpellAbilities()) {
if (s instanceof AbilityStatic && s.isTemporary()) {
getSource().removeSpellAbility(s);
}
}
getSource().removeChangedCardTraits(getTimestamp());
}
// modify players
......@@ -273,22 +267,12 @@ public class StaticEffect {
// the view is updated in GameAction#checkStaticAbilities to avoid flickering
// remove keywords
// TODO regular keywords currently don't try to use keyword multiplier
// (Although nothing uses it at this time)
if (hasParam("AddKeyword") || hasParam("RemoveKeyword")
|| hasParam("RemoveAllAbilities")) {
affectedCard.removeChangedCardKeywords(getTimestamp());
}
// remove abilities
if (hasParam("AddAbility") || hasParam("GainsAbilitiesOf")) {
for (final SpellAbility s : affectedCard.getSpellAbilities().threadSafeIterable()) {
if (s.isTemporary()) {
affectedCard.removeSpellAbility(s, false);
}
}
}
if (addHiddenKeywords != null) {
for (final String k : addHiddenKeywords) {
affectedCard.removeHiddenExtrinsicKeyword(k);
......@@ -296,8 +280,10 @@ public class StaticEffect {
}
// remove abilities
if (hasParam("RemoveAllAbilities") || hasParam("RemoveIntrinsicAbilities")) {
affectedCard.unSuppressCardTraits();
if (hasParam("AddAbility") || hasParam("GainsAbilitiesOf")
|| hasParam("AddTrigger") || hasParam("AddStaticAbility") || hasParam("AddReplacementEffects")
|| hasParam("RemoveAllAbilities") || hasParam("RemoveIntrinsicAbilities")) {
affectedCard.removeChangedCardTraits(getTimestamp());
}
// remove Types
......
......@@ -80,4 +80,13 @@ public class StaticEffects {
public Iterable<StaticEffect> getEffects() {
return staticEffects.values();
}
public boolean removeStaticEffect(final StaticAbility staticAbility) {
final StaticEffect currentEffect = staticEffects.remove(staticAbility);
if (currentEffect == null) {
return false;
}
currentEffect.remove();
return true;
}
}
......@@ -14,19 +14,15 @@ import forge.game.player.Player;
import forge.game.replacement.ReplacementEffect;
import forge.game.replacement.ReplacementHandler;
import forge.game.spellability.SpellAbility;
import forge.game.staticability.StaticAbility;
import forge.game.trigger.Trigger;
import forge.game.trigger.TriggerHandler;
import forge.game.zone.ZoneType;
import forge.util.collect.FCollectionView;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import com.google.common.collect.ImmutableList;
public class AnimateAllEffect extends AnimateEffectBase {
@Override
......@@ -160,30 +156,16 @@ public class AnimateAllEffect extends AnimateEffectBase {
final String actualAbility = host.getSVar(s);
final SpellAbility grantedAbility = AbilityFactory.getAbility(actualAbility, c);
addedAbilities.add(grantedAbility);
c.addSpellAbility(grantedAbility);
}
}
// remove abilities
final List<SpellAbility> removedAbilities = new ArrayList<>();
if (sa.hasParam("OverwriteAbilities") || removeAll || removeIntrinsic) {
for (final SpellAbility ab : c.getSpellAbilities()) {
if (ab.isAbility()) {
if (removeAll
|| (ab.isIntrinsic() && removeIntrinsic && !ab.isBasicLandAbility())) {
ab.setTemporarilySuppressed(true);
removedAbilities.add(ab);
}
}
}
}
// give replacement effects
final List<ReplacementEffect> addedReplacements = new ArrayList<>();
if (replacements.size() > 0) {
for (final String s : replacements) {
final String actualReplacement = host.getSVar(s);
final ReplacementEffect parsedReplacement = ReplacementHandler.parseReplacement(actualReplacement, c, false);
addedReplacements.add(c.addReplacementEffect(parsedReplacement));
addedReplacements.add(parsedReplacement);
}
}
// Grant triggers
......@@ -192,45 +174,12 @@ public class AnimateAllEffect extends AnimateEffectBase {
for (final String s : triggers) {
final String actualTrigger = host.getSVar(s);
final Trigger parsedTrigger = TriggerHandler.parseTrigger(actualTrigger, c, false);
addedTriggers.add(c.addTrigger(parsedTrigger));
addedTriggers.add(parsedTrigger);
}
}
// suppress triggers from the animated card
final List<Trigger> removedTriggers = new ArrayList<>();
if (sa.hasParam("OverwriteTriggers") || removeAll || removeIntrinsic) {
final FCollectionView<Trigger> triggersToRemove = c.getTriggers();
for (final Trigger trigger : triggersToRemove) {
if (removeIntrinsic && !trigger.isIntrinsic()) {
continue;
}
trigger.setSuppressed(true); // why this not TemporarilySuppressed?
removedTriggers.add(trigger);
}
}
// suppress static abilities from the animated card
final List<StaticAbility> removedStatics = new ArrayList<>();
if (sa.hasParam("OverwriteStatics") || removeAll || removeIntrinsic) {
for (final StaticAbility stAb : c.getStaticAbilities()) {
if (removeIntrinsic && !stAb.isIntrinsic()) {
continue;
}
stAb.setTemporarilySuppressed(true);
removedStatics.add(stAb);
}
}
// suppress static abilities from the animated card
final List<ReplacementEffect> removedReplacements = new ArrayList<>();
if (sa.hasParam("OverwriteReplacements") || removeAll || removeIntrinsic) {
for (final ReplacementEffect re : c.getReplacementEffects()) {
if (removeIntrinsic && !re.isIntrinsic()) {
continue;
}
re.setTemporarilySuppressed(true);
removedReplacements.add(re);
}
if (!addedAbilities.isEmpty() || !addedTriggers.isEmpty() || !addedReplacements.isEmpty()) {
c.addChangedCardTraits(addedAbilities, null, addedTriggers, addedReplacements, null, removeAll, false, removeIntrinsic, timestamp);
}
// give sVars
......@@ -247,27 +196,8 @@ public class AnimateAllEffect extends AnimateEffectBase {
@Override
public void run() {
doUnanimate(c, sa, finalDesc, hiddenKeywords,
addedAbilities, addedTriggers, addedReplacements,
ImmutableList.of(), timestamp);
for (final SpellAbility sa : removedAbilities) {
sa.setTemporarilySuppressed(false);
}
// give back suppressed triggers
for (final Trigger t : removedTriggers) {
t.setSuppressed(false);
}
// give back suppressed static abilities
for (final StaticAbility s : removedStatics) {
s.setTemporarilySuppressed(false);
}
// give back suppressed replacement effects
for (final ReplacementEffect re : removedReplacements) {
re.setTemporarilySuppressed(false);
}
doUnanimate(c, sa, hiddenKeywords, timestamp);
game.fireEvent(new GameEventCardStatsChanged(c));
}
};
......
......@@ -162,25 +162,15 @@ public class AnimateEffect extends AnimateEffectBase {
// remove abilities
final List<SpellAbility> removedAbilities = Lists.newArrayList();
boolean clearAbilities = sa.hasParam("OverwriteAbilities");
boolean clearSpells = sa.hasParam("OverwriteSpells");
boolean removeAll = sa.hasParam("RemoveAllAbilities");
boolean removeIntrinsic = sa.hasParam("RemoveIntrinsicAbilities");
if (clearAbilities || clearSpells || removeAll) {
for (final SpellAbility ab : c.getSpellAbilities()) {
if (removeAll
|| (ab.isIntrinsic() && removeIntrinsic && !ab.isBasicLandAbility())
|| (ab.isAbility() && clearAbilities)
|| (ab.isSpell() && clearSpells)) {
ab.setTemporarilySuppressed(true);
removedAbilities.add(ab);
}
}
if (clearSpells) {
removedAbilities.addAll(Lists.newArrayList(c.getSpells()));
}
if (sa.hasParam("RemoveThisAbility") && !removedAbilities.contains(sa)) {
c.removeSpellAbility(sa);
removedAbilities.add(sa);
}
......@@ -189,9 +179,7 @@ public class AnimateEffect extends AnimateEffectBase {
if (abilities.size() > 0) {
for (final String s : abilities) {
final String actualAbility = source.getSVar(s);
final SpellAbility grantedAbility = AbilityFactory.getAbility(actualAbility, c);
addedAbilities.add(grantedAbility);
c.addSpellAbility(grantedAbility);
addedAbilities.add(AbilityFactory.getAbility(actualAbility, c));
}
}
......@@ -201,7 +189,7 @@ public class AnimateEffect extends AnimateEffectBase {
for (final String s : triggers) {
final String actualTrigger = source.getSVar(s);
final Trigger parsedTrigger = TriggerHandler.parseTrigger(actualTrigger, c, false);
addedTriggers.add(c.addTrigger(parsedTrigger));
addedTriggers.add(parsedTrigger);
}
}
......@@ -211,19 +199,7 @@ public class AnimateEffect extends AnimateEffectBase {
for (final String s : replacements) {
final String actualReplacement = source.getSVar(s);
final ReplacementEffect parsedReplacement = ReplacementHandler.parseReplacement(actualReplacement, c, false);
addedReplacements.add(c.addReplacementEffect(parsedReplacement));
}
}
// suppress triggers from the animated card
final List<Trigger> removedTriggers = Lists.newArrayList();
if (sa.hasParam("OverwriteTriggers") || removeAll || removeIntrinsic) {
for (final Trigger trigger : c.getTriggers()) {
if (removeIntrinsic && !trigger.isIntrinsic()) {
continue;
}
trigger.setSuppressed(true); // why this not TemporarilySuppressed?
removedTriggers.add(trigger);
addedReplacements.add(parsedReplacement);
}
}
......@@ -233,7 +209,7 @@ public class AnimateEffect extends AnimateEffectBase {
if (stAbs.size() > 0) {
for (final String s : stAbs) {
final String actualAbility = source.getSVar(s);
addedStaticAbilities.add(c.addStaticAbility(actualAbility));
addedStaticAbilities.add(new StaticAbility(actualAbility, c));
}
}
......@@ -251,30 +227,6 @@ public class AnimateEffect extends AnimateEffectBase {
}
}
// suppress static abilities from the animated card
final List<StaticAbility> removedStatics = Lists.newArrayList();
if (sa.hasParam("OverwriteStatics") || removeAll || removeIntrinsic) {
for (final StaticAbility stAb : c.getStaticAbilities()) {
if (removeIntrinsic && !stAb.isIntrinsic()) {
continue;
}
stAb.setTemporarilySuppressed(true);
removedStatics.add(stAb);
}
}
// suppress static abilities from the animated card
final List<ReplacementEffect> removedReplacements = Lists.newArrayList();
if (sa.hasParam("OverwriteReplacements") || removeAll || removeIntrinsic) {
for (final ReplacementEffect re : c.getReplacementEffects()) {
if (removeIntrinsic && !re.isIntrinsic()) {
continue;
}
re.setTemporarilySuppressed(true);
removedReplacements.add(re);
}
}
// give Remembered
if (animateRemembered != null) {
for (final Object o : AbilityUtils.getDefinedObjects(source, animateRemembered, sa)) {
......@@ -287,34 +239,39 @@ public class AnimateEffect extends AnimateEffectBase {
@Override
public void run() {
doUnanimate(c, sa, finalDesc, hiddenKeywords,
addedAbilities, addedTriggers, addedReplacements,
addedStaticAbilities, timestamp);
doUnanimate(c, sa, hiddenKeywords, timestamp);
c.removeChangedName(timestamp);
c.updateStateForView();
game.fireEvent(new GameEventCardStatsChanged(c));
}
};
for (final SpellAbility sa : removedAbilities) {
sa.setTemporarilySuppressed(false);
}
// give back suppressed triggers
for (final Trigger t : removedTriggers) {
t.setSuppressed(false);
}
// give back suppressed static abilities
for (final StaticAbility s : removedStatics) {
s.setTemporarilySuppressed(false);
if (sa.hasParam("RevertCost")) {
final ManaCost cost = new ManaCost(new ManaCostParser(sa.getParam("RevertCost")));
final String desc = this.getStackDescription(sa);
final SpellAbility revertSA = new AbilityStatic(c, cost) {
@Override
public void resolve() {
unanimate.run();
}
// give back suppressed replacement effects
for (final ReplacementEffect re : removedReplacements) {
re.setTemporarilySuppressed(false);
@Override
public String getDescription() {
return cost + ": End Effect: " + desc;
}
}
};
};
addedAbilities.add(revertSA);
}
// after unanimate to add RevertCost
if (removeAll || removeIntrinsic
|| !addedAbilities.isEmpty() || !removedAbilities.isEmpty() || !addedTriggers.isEmpty()
|| !addedReplacements.isEmpty() || !addedStaticAbilities.isEmpty()) {
c.addChangedCardTraits(addedAbilities, removedAbilities, addedTriggers, addedReplacements,
addedStaticAbilities, removeAll, false, removeIntrinsic, timestamp);
}
if (!permanent) {
if (sa.hasParam("UntilEndOfCombat")) {
......@@ -343,22 +300,6 @@ public class AnimateEffect extends AnimateEffectBase {
}
}
if (sa.hasParam("RevertCost")) {
final ManaCost cost = new ManaCost(new ManaCostParser(sa.getParam("RevertCost")));
final String desc = this.getStackDescription(sa);
final SpellAbility revertSA = new AbilityStatic(c, cost) {
@Override
public void resolve() {
unanimate.run();
c.removeSpellAbility(this);
}
@Override
public String getDescription() {
return cost + ": End Effect: " + desc;
}
};
c.addSpellAbility(revertSA);
}
game.fireEvent(new GameEventCardStatsChanged(c));
}
......
......@@ -20,10 +20,8 @@ package forge.game.ability.effects;
import forge.card.CardType;
import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card;
import forge.game.replacement.ReplacementEffect;
import forge.game.spellability.SpellAbility;
import forge.game.staticability.StaticAbility;
import forge.game.trigger.Trigger;
import java.util.List;
public abstract class AnimateEffectBase extends SpellAbilityEffect {
......@@ -128,14 +126,8 @@ public abstract class AnimateEffectBase extends SpellAbilityEffect {
* @param timestamp
* a long.
*/
static void doUnanimate(final Card c, SpellAbility sa, final String colorDesc,
final List<String> hiddenKeywords, final List<SpellAbility> addedAbilities,
final List<Trigger> addedTriggers, final List<ReplacementEffect> addedReplacements,
final List<StaticAbility> addedStaticAbilities, final long timestamp) {
if (sa.hasParam("LastsIndefinitely")) {
return;
}
static void doUnanimate(final Card c, SpellAbility sa,
final List<String> hiddenKeywords, final long timestamp) {
c.removeNewPT(timestamp);
......@@ -144,26 +136,12 @@ public abstract class AnimateEffectBase extends SpellAbilityEffect {
c.removeChangedCardTypes(timestamp);
c.removeColor(timestamp);
c.removeChangedCardTraits(timestamp);
for (final String k : hiddenKeywords) {
c.removeHiddenExtrinsicKeyword(k);
}
for (final SpellAbility saAdd : addedAbilities) {
c.removeSpellAbility(saAdd);
}
for (final Trigger t : addedTriggers) {
c.removeTrigger(t);
}
for (final ReplacementEffect rep : addedReplacements) {
c.removeReplacementEffect(rep);
}
for (final StaticAbility stAb : addedStaticAbilities) {
c.removeStaticAbility(stAb);
}
// any other unanimate cleanup
if (!c.isCreature()) {
c.unEquipAllCards();
......
......@@ -158,7 +158,8 @@ public class EffectEffect extends SpellAbilityEffect {
if (effectStaticAbilities != null) {
for (final String s : effectStaticAbilities) {
final StaticAbility addedStaticAbility = eff.addStaticAbility(AbilityUtils.getSVar(sa, s));
addedStaticAbility.setIntrinsic(true);
if (addedStaticAbility != null) //prevent npe casting adventure card spell
addedStaticAbility.setIntrinsic(true);
}
}
......
......@@ -58,7 +58,7 @@ public abstract class RegenerateBaseEffect extends SpellAbilityEffect {
+ " | TriggerDescription$ " + trigSA.getDescription();
final Trigger trigger = TriggerHandler.parseTrigger(trigStr, eff, true);
trigger.setOverridingAbility(trigSA);
eff.moveTrigger(trigger);
eff.addTrigger(trigger);
}
// Copy text changes
......
......@@ -55,7 +55,6 @@ public class RestartGameEffect extends SpellAbilityEffect {
forge.game.trigger.Trigger.resetIDs();
TriggerHandler trigHandler = game.getTriggerHandler();
trigHandler.clearDelayedTrigger();
trigHandler.cleanUpTemporaryTriggers();
trigHandler.suppressMode(TriggerType.ChangesZone);
game.getStack().reset();
......
package forge.game.card;
import java.util.Collection;
import java.util.List;
import com.google.common.collect.Lists;
import forge.game.replacement.ReplacementEffect;
import forge.game.spellability.SpellAbility;
import forge.game.staticability.StaticAbility;
import forge.game.trigger.Trigger;
public class CardTraitChanges implements Cloneable {
private List<Trigger> triggers = Lists.newArrayList();
private List<ReplacementEffect> replacements = Lists.newArrayList();
private List<SpellAbility> abilities = Lists.newArrayList();
private List<StaticAbility> staticAbilities = Lists.newArrayList();
private List<SpellAbility> removedAbilities = Lists.newArrayList();
private boolean removeAll;
private boolean removeNonMana;
private boolean removeIntrinsic;
public CardTraitChanges(Collection<SpellAbility> spells, Collection<SpellAbility> removedAbilities,
Collection<Trigger> trigger, Collection<ReplacementEffect> res, Collection<StaticAbility> st,
boolean removeAll, boolean removeNonMana, boolean removeIntrinsic) {
if (spells != null) {
this.abilities.addAll(spells);
}
if (removedAbilities != null) {
this.removedAbilities.addAll(removedAbilities);
}
if (trigger != null) {
this.triggers.addAll(trigger);
}
if (res != null) {
this.replacements.addAll(res);
}
if (st != null) {
this.staticAbilities.addAll(st);
}
this.removeAll = removeAll;
this.removeNonMana = removeNonMana;
this.removeIntrinsic = removeIntrinsic;
}
/**
* @return the triggers
*/
public Collection<Trigger> getTriggers() {
return triggers;
}
/**
* @return the replacements
*/
public Collection<ReplacementEffect> getReplacements() {
return replacements;
}
/**
* @return the abilities
*/
public Collection<SpellAbility> getAbilities() {
return abilities;
}
/**
* @return the abilities
*/
public Collection<SpellAbility> getRemovedAbilities() {
return removedAbilities;
}
/**
* @return the staticAbilities
*/
public Collection<StaticAbility> getStaticAbilities() {
return staticAbilities;
}
public boolean isRemoveAll() {
return removeAll;
}
public boolean isRemoveNonMana() {
return removeNonMana;
}
public boolean isRemoveIntrinsic() {
return removeIntrinsic;
}
public CardTraitChanges copy(Card host, boolean lki) {
try {
CardTraitChanges result = (CardTraitChanges) super.clone();
result.abilities = Lists.newArrayList();
for (SpellAbility sa : this.abilities) {
result.abilities.add(sa.copy(host, lki));
}
result.removedAbilities = Lists.newArrayList();
for (SpellAbility sa : this.removedAbilities) {
result.removedAbilities.add(sa.copy(host, lki));
}
result.triggers = Lists.newArrayList();
for (Trigger tr : this.triggers) {
result.triggers.add(tr.copy(host, lki));
}
result.replacements = Lists.newArrayList();
for (ReplacementEffect re : this.replacements) {
result.replacements.add(re.copy(host, lki));
}
result.staticAbilities = Lists.newArrayList();
for (StaticAbility sa : this.staticAbilities) {
result.staticAbilities.add(sa.copy(host, lki));
}
return result;
} catch (final Exception ex) {
throw new RuntimeException("CardTraitChanges : clone() error", ex);
}
}
}
......@@ -29,9 +29,7 @@ import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.player.Player;
import forge.game.replacement.ReplacementEffect;
import forge.game.spellability.*;
import forge.game.trigger.Trigger;
import forge.game.zone.ZoneType;
import forge.util.TextUtil;
import forge.util.collect.FCollection;
......@@ -240,23 +238,6 @@ public final class CardUtil {
newCopy.setType(new CardType(in.getType()));
newCopy.setToken(in.isToken());
// extra copy non Intrinsic traits
for (SpellAbility sa : in.getSpellAbilities()) {
if (!sa.isIntrinsic()) {
newCopy.addSpellAbility(sa.copy(newCopy, true));
}
}
for (Trigger tr : in.getTriggers()) {
if (!tr.isIntrinsic()) {
newCopy.moveTrigger(tr.copy(newCopy, true));
}
}
for (ReplacementEffect re : in.getReplacementEffects()) {
if (!re.isIntrinsic()) {
newCopy.addReplacementEffect(re.copy(newCopy, true));
}
}
// lock in the current P/T without bonus from counters
newCopy.setBasePower(in.getCurrentPower() + in.getTempPowerBoost());
newCopy.setBaseToughness(in.getCurrentToughness() + in.getTempToughnessBoost());
......@@ -293,6 +274,7 @@ public final class CardUtil {
newCopy.setChangedCardKeywords(in.getChangedCardKeywords());
newCopy.setChangedCardTypes(in.getChangedCardTypesMap());
newCopy.setChangedCardNames(in.getChangedCardNames());
newCopy.setChangedCardTraits(in.getChangedCardTraits());
newCopy.copyChangedTextFrom(in);
......
......@@ -1178,7 +1178,7 @@ public class Player extends GameEntity implements Comparable<Player> {
com.remove(eff);
eff.setStaticAbilities(Lists.newArrayList());
}
this.updateZoneForView(com);
this.updateZoneForView(com);
}
@Override
......
......@@ -193,7 +193,6 @@ public abstract class ReplacementEffect extends TriggerReplacementBase {
res.setActiveZone(validHostZones);
res.setLayer(getLayer());
res.setTemporary(isTemporary());
return res;
}
......
......@@ -356,31 +356,4 @@ public class ReplacementHandler {
return ret;
}
public void cleanUpTemporaryReplacements() {
game.forEachCardInGame(new Visitor<Card>() {
@Override
public boolean visit(Card c) {
List<ReplacementEffect> toRemove = Lists.newArrayList();
for (ReplacementEffect rep : c.getReplacementEffects()) {
if (rep.isTemporary()) {
toRemove.add(rep);
}
}
for (ReplacementEffect rep : toRemove) {
c.removeReplacementEffect(rep);
}
return true;
}
});
game.forEachCardInGame(new Visitor<Card>() {
@Override
public boolean visit(Card c) {
for (int i = 0; i < c.getReplacementEffects().size(); i++) {
c.getReplacementEffects().get(i).setTemporarilySuppressed(false);
}
return true;
}
});
}
}
......@@ -32,6 +32,15 @@ public final class SpellAbilityPredicates extends CardTraitPredicates {
}
};
}
public static final Predicate<SpellAbility> isManaAbility() {
return new Predicate<SpellAbility>() {
@Override
public boolean apply(final SpellAbility sa) {
return sa.isManaAbility();
}
};
}
public static final Predicate<SpellAbility> isIntrinsic() {
return new Predicate<SpellAbility>() {
......
......@@ -159,14 +159,14 @@ public class StaticAbility extends CardTraitBase implements IIdentifiable, Clone
}
if (hasParam("RemoveAllAbilities") || hasParam("GainsAbilitiesOf")) {
layers.add(StaticAbilityLayer.ABILITIES1);
layers.add(StaticAbilityLayer.ABILITIES);
}
if (hasParam("AddKeyword") || hasParam("AddAbility")
|| hasParam("AddTrigger") || hasParam("RemoveTriggers")
|| hasParam("RemoveKeyword") || hasParam("AddReplacementEffects")
|| hasParam("AddStaticAbility") || hasParam("AddSVar")) {
layers.add(StaticAbilityLayer.ABILITIES2);
layers.add(StaticAbilityLayer.ABILITIES);
}
if (hasParam("CharacteristicDefining")) {
......@@ -183,7 +183,7 @@ public class StaticAbility extends CardTraitBase implements IIdentifiable, Clone
if (hasParam("AddHiddenKeyword")) {
// special rule for can't have or gain
if (getParam("AddHiddenKeyword").contains("can't have or gain")) {
layers.add(StaticAbilityLayer.ABILITIES1);
layers.add(StaticAbilityLayer.ABILITIES);
}
layers.add(StaticAbilityLayer.RULES);
}
......@@ -259,14 +259,14 @@ public class StaticAbility extends CardTraitBase implements IIdentifiable, Clone
}
public final CardCollectionView applyContinuousAbilityBefore(final StaticAbilityLayer layer, final CardCollectionView preList) {
if (!shouldApplyContinuousAbility(layer, false)) {
if (!shouldApplyContinuousAbility(layer)) {
return null;
}
return StaticAbilityContinuous.applyContinuousAbility(this, layer, preList);
}
public final CardCollectionView applyContinuousAbility(final StaticAbilityLayer layer, final CardCollectionView affected) {
if (!shouldApplyContinuousAbility(layer, true)) {
if (!shouldApplyContinuousAbility(layer)) {
return null;
}
return StaticAbilityContinuous.applyContinuousAbility(this, affected, layer);
......@@ -286,14 +286,8 @@ public class StaticAbility extends CardTraitBase implements IIdentifiable, Clone
* affects the specified layer, it's not suppressed, and its
* conditions are fulfilled.
*/
private boolean shouldApplyContinuousAbility(final StaticAbilityLayer layer, final boolean ignoreTempSuppression) {
final boolean isSuppressed;
if (ignoreTempSuppression) {
isSuppressed = this.isNonTempSuppressed();
} else {
isSuppressed = this.isSuppressed();
}
return getParam("Mode").equals("Continuous") && layers.contains(layer) && !isSuppressed && this.checkConditions();
private boolean shouldApplyContinuousAbility(final StaticAbilityLayer layer) {
return getParam("Mode").equals("Continuous") && layers.contains(layer) && !isSuppressed() && this.checkConditions();
}
// apply the ability if it has the right mode
......
......@@ -18,11 +18,8 @@ public enum StaticAbilityLayer {
/** Layer 5 for color-changing effects. */
COLOR,
/** Layer 6 for ability-removing and -copying effects. */
ABILITIES1,
/** Layer 6 for ability-granting effects. */
ABILITIES2,
/** Layer 6 for ability effects. */
ABILITIES,
/** Layer 7a for characteristic-defining power/toughness effects. */
CHARACTERISTIC,
......@@ -37,5 +34,5 @@ public enum StaticAbilityLayer {
RULES;
public final static ImmutableList<StaticAbilityLayer> CONTINUOUS_LAYERS =
ImmutableList.of(COPY, CONTROL, TEXT, TYPE, COLOR, ABILITIES1, ABILITIES2, CHARACTERISTIC, SETPT, MODIFYPT, RULES);
ImmutableList.of(COPY, CONTROL, TEXT, TYPE, COLOR, ABILITIES, CHARACTERISTIC, SETPT, MODIFYPT, RULES);
}
......@@ -561,7 +561,6 @@ public abstract class Trigger extends TriggerReplacementBase {
copy.setTriggerPhases(Lists.newArrayList(validPhases));
}
copy.setActiveZone(validHostZones);
copy.setTemporary(isTemporary());
return copy;
}
......
......@@ -67,42 +67,6 @@ public class TriggerHandler {
}
public final void cleanUpTemporaryTriggers() {
game.forEachCardInGame(new Visitor<Card>() {
@Override
public boolean visit(Card c) {
boolean changed = false;
List<Trigger> toRemove = Lists.newArrayList();
for (Trigger t : c.getTriggers()) {
if (t.isTemporary()) {
toRemove.add(t);
}
}
for (Trigger t : toRemove) {
changed = true;
c.removeTrigger(t);
}
if (changed) {
c.updateStateForView();
}
return true;
}
});
game.forEachCardInGame(new Visitor<Card>() {
@Override
public boolean visit(Card c) {
boolean changed = false;
for (int i = 0; i < c.getTriggers().size(); i++) {
if (c.getTriggers().get(i).isSuppressed()) {
c.getTriggers().get(i).setTemporarilySuppressed(false);
changed = true;
}
}
if (changed) {
c.updateStateForView();
}
return true;
}
});
}
public final boolean hasDelayedTriggers() {
......@@ -699,9 +663,6 @@ public class TriggerHandler {
Player p = regtrig.getHostCard().getController();
p.getZone(ZoneType.Command).remove(regtrig.getHostCard());
}
else {
regtrig.getHostCard().removeTrigger(regtrig);
}
}
}
......
[metadata]
Name:Possibility Storm - Throne of Eldraine #00 (Pre-release Puzzle)
URL:http://www.possibilitystorm.com/wp-content/uploads/2019/10/130.-ELD001.jpg
Goal:Win
Turns:1
Difficulty:Uncommon
Description:Win this turn.
[state]
humanlife=20
ailife=12
turn=1
activeplayer=human
activephase=MAIN1
humanhand=Giant Opportunity;Mirrormade;Curious Pair;Frogify
humanbattlefield=Witch's Oven;Wicked Wolf;Maraleaf Rider;Oko, Thief of Crowns|Counters:LOYALTY=6;Forest;Forest;Forest;Island;Island;Island
aibattlefield=Wojek Bodyguard;Loyal Pegasus
humanprecast=Oko, Thief of Crowns:1