Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -91,39 +91,36 @@ public static void doAnimate(final Card c, final SpellAbility sa, final Integer
// Alchemy "incorporate" cost
if (sa.hasParam("Incorporate")) {
final ManaCost incMCost = new ManaCost(sa.getParam("Incorporate"));
PerpetualIncorporate p = new PerpetualIncorporate(timestamp, incMCost);
c.addPerpetual(p);
p.applyEffect(c);
c.addPerpetual(new PerpetualIncorporate(incMCost), timestamp);
}
if (sa.hasParam("ManaCost")) {
final ManaCost manaCost = new ManaCost(sa.getParam("ManaCost"));
if (perpetual) {
PerpetualManaCost p = new PerpetualManaCost(timestamp, manaCost);
c.addPerpetual(p);
p.applyEffect(c);
c.addPerpetual(new PerpetualManaCost(manaCost), timestamp);
}
}

if (!addType.isEmpty() || !removeType.isEmpty() || addAllCreatureTypes || !remove.isEmpty()) {
if (perpetual) {
c.addPerpetual(new PerpetualTypes(timestamp, addType, removeType, remove));
c.addPerpetual(new PerpetualTypes(timestamp, addType, removeType, remove), timestamp);
}
c.addChangedCardTypes(addType, removeType, addAllCreatureTypes, remove, timestamp, 0, true, false);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't all be else now?

}

if (!keywords.isEmpty() || !removeKeywords.isEmpty() || removeAbilities != null) {
if (perpetual) {
c.addPerpetual(new PerpetualKeywords(timestamp, keywords, removeKeywords, removeAbilities != null));
c.addPerpetual(new PerpetualKeywords(timestamp, keywords, removeKeywords, removeAbilities != null), timestamp);
}
c.addChangedCardKeywords(keywords, removeKeywords, removeAbilities != null, timestamp, null);
}

// do this after changing types in case it wasn't a creature before
if (power != null || toughness != null) {
if (perpetual) {
c.addPerpetual(new PerpetualNewPT(timestamp, power, toughness));
c.addPerpetual(new PerpetualNewPT(power, toughness), timestamp);
} else {
c.addNewPT(power, toughness, timestamp, 0);
}
c.addNewPT(power, toughness, timestamp, 0);
} else if (!wasCreature && c.isCreature()) {
c.updatePTforView();
}
Expand All @@ -139,9 +136,10 @@ public static void doAnimate(final Card c, final SpellAbility sa, final Integer
if (colors != null) {
final boolean overwrite = sa.hasParam("OverwriteColors");
if (perpetual) {
c.addPerpetual(new PerpetualColors(timestamp, colors, overwrite));
c.addPerpetual(new PerpetualColors(colors, overwrite), timestamp);
} else {
c.addColor(colors, !overwrite, timestamp, null);
}
c.addColor(colors, !overwrite, timestamp, null);
}

if (sa.hasParam("LeaveBattlefield")) {
Expand Down Expand Up @@ -224,7 +222,7 @@ public String getDescription() {
ICardTraitChanges changes = c.addChangedCardTraits(addedAbilities, removedAbilities, addedTriggers, addedReplacements,
addedStaticAbilities, removeAbilities, timestamp, 0);
if (perpetual) {
c.addPerpetual(new PerpetualAbilities(timestamp, changes));
c.addPerpetual(new PerpetualAbilities(timestamp, changes), timestamp);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,12 @@ public void resolve(SpellAbility sa) {
final long timestamp = game.getNextTimestamp();

if (perpetual) {
c1.addPerpetual(new PerpetualNewPT(timestamp, power2, null));
c2.addPerpetual(new PerpetualNewPT(timestamp, power1, null));
c1.addPerpetual(new PerpetualNewPT(power2, null), timestamp);
c2.addPerpetual(new PerpetualNewPT(power1, null), timestamp);
} else {
c1.addNewPT(power2, null, timestamp, 0);
c2.addNewPT(power1, null, timestamp, 0);
}
c1.addNewPT(power2, null, timestamp, 0);
c2.addNewPT(power1, null, timestamp, 0);

game.fireEvent(new GameEventCardStatsChanged(c1));
game.fireEvent(new GameEventCardStatsChanged(c2));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,16 @@ private static void applyPumpAll(final SpellAbility sa,

if (a != 0 || d != 0) {
if (perpetual) {
tgtC.addPerpetual(new PerpetualPTBoost(timestamp, a, d));
tgtC.addPerpetual(new PerpetualPTBoost(a, d), timestamp);
} else {
tgtC.addPTBoost(a, d, timestamp, 0);
}
tgtC.addPTBoost(a, d, timestamp, 0);
redrawPT = true;
}

if (!kws.isEmpty()) {
if (perpetual) {
tgtC.addPerpetual(new PerpetualKeywords(timestamp, kws, null, false));
tgtC.addPerpetual(new PerpetualKeywords(timestamp, kws, null, false), timestamp);
}
tgtC.addChangedCardKeywords(kws, null, false, timestamp, null);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,16 @@ private static void applyPump(final SpellAbility sa, final Card applyTo,

if (a != 0 || d != 0) {
if (perpetual) {
gameCard.addPerpetual(new PerpetualPTBoost(timestamp, a, d));
gameCard.addPerpetual(new PerpetualPTBoost(a, d), timestamp);
} else {
gameCard.addPTBoost(a, d, timestamp, 0);
}
gameCard.addPTBoost(a, d, timestamp, 0);
redrawPT = true;
}

if (!kws.isEmpty()) {
if (perpetual) {
gameCard.addPerpetual(new PerpetualKeywords(timestamp, kws, Lists.newArrayList(), false));
gameCard.addPerpetual(new PerpetualKeywords(timestamp, kws, Lists.newArrayList(), false), timestamp);
}
gameCard.addChangedCardKeywords(kws, Lists.newArrayList(), false, timestamp, null);
}
Expand Down
27 changes: 23 additions & 4 deletions forge-game/src/main/java/forge/game/card/Card.java
Original file line number Diff line number Diff line change
Expand Up @@ -4630,15 +4630,21 @@ public final boolean hasIntensity() {
}

private List<PerpetualInterface> perpetual = new ArrayList<>();
private Multimap<PerpetualInterface, StaticAbility> perpetualEffects = MultimapBuilder.hashKeys().arrayListValues().build();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove List above

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not all are transformed yet, the list will be removed later

(i don't know yet if the new one needs to be a Multimap or if a List is enough)

public final boolean hasPerpetual() {
return !perpetual.isEmpty();
}
public final List<PerpetualInterface> getPerpetual() {
return perpetual;
}

public final void addPerpetual(PerpetualInterface p) {
public final void addPerpetual(PerpetualInterface p, long timestamp) {
perpetual.add(p);
StaticAbility st = p.createEffect(this);
if (st != null) {
st.putParam("Timestamp", String.valueOf(timestamp));
this.perpetualEffects.put(p, st);
}
}

public final void removePerpetual(final long timestamp) {
Expand All @@ -4653,16 +4659,28 @@ public final void removePerpetual(final long timestamp) {
}

public final void setPerpetual(final Card oldCard) {
setPerpetual(oldCard, true);
setPerpetual(oldCard, false);
}

public final void setPerpetual(final Card oldCard, boolean applyEffects) {
public final void setPerpetual(final Card oldCard, boolean lki) {
perpetual = oldCard.getPerpetual();
if (applyEffects) {
if (!lki) {
for (PerpetualInterface p : perpetual) {
p.applyEffect(this);
}
}

long currentGameTimestamp = this.getGame().getTimestamp();
for (Map.Entry<PerpetualInterface, StaticAbility> e : oldCard.perpetualEffects.entries()) {
StaticAbility st = e.getValue().copy(this, lki);
long oldTimestamp = Long.valueOf(st.getParam("Timestamp"));
if (!lki && oldTimestamp > 0) {
// change zone sets the timestamp of negative infinite, but still relative
// use current game timestamp to shift these timestamps back
st.putParam("Timestamp", String.valueOf(Long.MIN_VALUE + oldTimestamp));
}
this.perpetualEffects.put(e.getKey(), st);
}
}

public final boolean isUntapped() {
Expand Down Expand Up @@ -7106,6 +7124,7 @@ public final FCollectionView<StaticAbility> getHiddenStaticAbilities() {
result.add(e.getValue());
}
}
result.addAll(this.perpetualEffects.values());
return result;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ public Card getLKICopy(Map<Integer, Card> cachedMap) {
// Don't re-apply perpetual effects - they're already copied via copyFrom().
// Re-applying would create duplicate ReplacementEffect objects that cause
// infinite recursion in getReplacementList for "enters tapped" effects.
newCopy.setPerpetual(copyFrom, false);
newCopy.setPerpetual(copyFrom, true);

newCopy.addRemembered(copyFrom.getRemembered());
newCopy.addImprintedCards(copyFrom.getImprintedCards());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
package forge.game.card.perpetual;

import java.util.stream.Collectors;

import forge.card.ColorSet;
import forge.card.MagicColor;
import forge.game.card.Card;
import forge.game.staticability.StaticAbility;

public record PerpetualColors(long timestamp, ColorSet colors, boolean overwrite) implements PerpetualInterface {

public record PerpetualColors(ColorSet colors, boolean overwrite) implements PerpetualInterface {
@Override
public long getTimestamp() {
return timestamp;
}
public StaticAbility createEffect(Card c) {
StringBuilder sb = new StringBuilder("Mode$ Continuous | AffectedDefined$ Self | EffectZone$ All | ");
sb.append( overwrite ? "SetColor" : "AddColor").append("$ ");
sb.append(colors.stream().map(MagicColor.Color::getName).collect(Collectors.joining(",")));

@Override
public void applyEffect(Card c) {
c.addColor(colors, !overwrite, timestamp, null);
return StaticAbility.create(sb.toString(), c, c.getCurrentState(), true);
}

}
Original file line number Diff line number Diff line change
@@ -1,19 +1,13 @@
package forge.game.card.perpetual;

import forge.card.ColorSet;
import forge.card.mana.ManaCost;
import forge.game.card.Card;
import forge.game.staticability.StaticAbility;

public record PerpetualIncorporate(long timestamp, ManaCost incorporate) implements PerpetualInterface {
public record PerpetualIncorporate(ManaCost incorporate) implements PerpetualInterface {
@Override
public long getTimestamp() {
return timestamp;
}

@Override
public void applyEffect(Card c) {
ColorSet colors = ColorSet.fromMask(incorporate.getColorProfile());
c.addChangedManaCost(incorporate, true, timestamp, (long) 0);
c.addColorByText(colors, true, timestamp, null);
public StaticAbility createEffect(Card c) {
String s = "Mode$ Continuous | AffectedDefined$ Self | EffectZone$ All | Incorporate$ " + incorporate.getShortString();
return StaticAbility.create(s, c, c.getCurrentState(), true);
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package forge.game.card.perpetual;

import forge.game.card.Card;
import forge.game.staticability.StaticAbility;

public interface PerpetualInterface {
long getTimestamp();
void applyEffect(Card c);
default long getTimestamp() { return -1; }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reminder to remove this later

default void applyEffect(Card c) {}

default StaticAbility createEffect(Card c) {return null;}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,12 @@

import forge.card.mana.ManaCost;
import forge.game.card.Card;
import forge.game.staticability.StaticAbility;

public record PerpetualManaCost(long timestamp, ManaCost manaCost) implements PerpetualInterface {
public record PerpetualManaCost(ManaCost manaCost) implements PerpetualInterface {
@Override
public long getTimestamp() {
return timestamp;
}

@Override
public void applyEffect(Card c) {
c.addChangedManaCost(manaCost, false, timestamp, (long) 0);
public StaticAbility createEffect(Card c) {
String s = "Mode$ Continuous | AffectedDefined$ Self | EffectZone$ All | ManaCost$ " + manaCost.getShortString();
return StaticAbility.create(s, c, c.getCurrentState(), true);
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
package forge.game.card.perpetual;

import forge.game.card.Card;
import forge.game.staticability.StaticAbility;

public record PerpetualNewPT(long timestamp, Integer power, Integer toughness) implements PerpetualInterface {

@Override
public long getTimestamp() {
return timestamp;
}

public record PerpetualNewPT(Integer power, Integer toughness) implements PerpetualInterface {
@Override
public void applyEffect(Card c) {
c.addNewPT(power, toughness, timestamp, (long) 0);
public StaticAbility createEffect(Card c) {
StringBuilder sb = new StringBuilder("Mode$ Continuous | AffectedDefined$ Self | EffectZone$ All ");
if (power != null) {
sb.append("| SetPower$ ").append(power);
}
if (toughness != null) {
sb.append("| SetToughness$ ").append(toughness);
}
return StaticAbility.create(sb.toString(), c, c.getCurrentState(), true);
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
package forge.game.card.perpetual;

import forge.game.card.Card;
import forge.game.staticability.StaticAbility;

public record PerpetualPTBoost(long timestamp, Integer power, Integer toughness) implements PerpetualInterface {

@Override
public long getTimestamp() {
return timestamp;
}

public record PerpetualPTBoost(Integer power, Integer toughness) implements PerpetualInterface {
@Override
public void applyEffect(Card c) {
c.addPTBoost(power, toughness, timestamp, (long) 0);
public StaticAbility createEffect(Card c) {
StringBuilder sb = new StringBuilder("Mode$ Continuous | AffectedDefined$ Self | EffectZone$ All ");
if (power != null) {
sb.append("| AddPower$ ").append(power);
}
if (toughness != null) {
sb.append("| AddToughness$ ").append(toughness);
}
return StaticAbility.create(sb.toString(), c, c.getCurrentState(), true);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public void testPerpetualEntersTappedReplacementEffect() {
Lists.newArrayList(re),
null, null
);
creature.addPerpetual(new PerpetualAbilities(timestamp, changes));
creature.addPerpetual(new PerpetualAbilities(timestamp, changes), timestamp);
creature.addChangedCardTraits(null, null, null,
Lists.newArrayList(re), null, null, timestamp, 0);

Expand Down