Skip to content
Merged
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 @@ -163,14 +163,7 @@ public void resolve(SpellAbility sa) {

// extra case for Epic to remove the keyword and the last part of the SpellAbility
if (sa.hasParam("Epic")) {
copy.getHostCard().getCurrentState().removeIntrinsicKeyword(Keyword.EPIC);
SpellAbility sub = copy;
while (sub.getSubAbility() != null && !sub.hasParam("Epic")) {
sub = sub.getSubAbility();
}
if (sub != null) {
sub.getParent().setSubAbility(sub.getSubAbility());
}
copy.getHostCard().removeIntrinsicKeyword(Keyword.EPIC);
}

copies.add(copy);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,10 @@ public void resolve(final SpellAbility sa) {
final Zone zone = tgtCard.getZone();
tgtCard = Card.fromPaperCard(tgtCard.getPaperCard(), controller);

if (sa.hasParam("Paradigm")) {
tgtCard.removeIntrinsicKeyword(Keyword.PARADIGM);
}

tgtCard.setGamePieceType(GamePieceType.TOKEN);
tgtCard.setZone(zone);
// to fix the CMC
Expand Down
12 changes: 3 additions & 9 deletions forge-game/src/main/java/forge/game/card/Card.java
Original file line number Diff line number Diff line change
Expand Up @@ -3206,7 +3206,7 @@ private StringBuilder abilityTextInstantSorcery(CardState state) {
sbBefore.append("\r\n\r\n");
} else if (keyword.equals("Conspire") || keyword.equals("Epic")
|| keyword.equals("Suspend") || keyword.equals("Jump-start")
|| keyword.equals("Fuse")) {
|| keyword.equals("Fuse") || keyword.equals("Paradigm")) {
sbAfter.append(keyword).append(" (").append(inst.getReminderText()).append(")");
sbAfter.append("\r\n");
} else if (keyword.startsWith("Casualty")) {
Expand Down Expand Up @@ -5275,14 +5275,8 @@ public final void addIntrinsicKeywords(final Iterable<String> s, boolean initTra
}
}

public final void removeIntrinsicKeyword(final String s) {
if (currentState.removeIntrinsicKeyword(s)) {
updateKeywords();
}
}

public final void removeIntrinsicKeyword(final KeywordInterface s) {
if (currentState.removeIntrinsicKeyword(s)) {
public final void removeIntrinsicKeyword(final Keyword k) {
if (currentState.removeIntrinsicKeyword(k)) {
updateKeywords();
}
}
Expand Down
21 changes: 20 additions & 1 deletion forge-game/src/main/java/forge/game/card/CardFactoryUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -2846,7 +2846,7 @@ else if (part instanceof CostCollectEvidence) {
// Epic does modify existing SA, and does not add new one

// Add the Epic effect as a subAbility
String dbStr = "DB$ Effect | Triggers$ EpicTrigger | StaticAbilities$ EpicCantBeCast | Duration$ Permanent | Epic$ True";
String dbStr = "DB$ Effect | Triggers$ EpicTrigger | StaticAbilities$ EpicCantBeCast | Duration$ Permanent | ConditionDefined$ Self | ConditionPresent$ Card.hasKeywordEpic";

final AbilitySub newSA = (AbilitySub) AbilityFactory.getAbility(dbStr, card);

Expand Down Expand Up @@ -3271,6 +3271,25 @@ public void resolve() {
newSA.setIntrinsic(intrinsic);
newSA.setAlternativeCost(AlternativeCost.Overload);
inst.addSpellAbility(newSA);
} else if (keyword.equals("Paradigm")) {
// Paradigm does modify existing SA, and does not add new one

// Add the Paradigm effect as a subAbility
String abExile = "DB$ ChangeZone | Defined$ Self | Origin$ Stack | Destination$ Exile";
final AbilitySub saExile = (AbilitySub) AbilityFactory.getAbility(abExile, card);

String dbStr = "DB$ Effect | Triggers$ ParadigmTrigger | Duration$ Permanent | ConditionDefined$ Self | ConditionPresent$ Card.hasKeywordParadigm";
final AbilitySub newSA = (AbilitySub) AbilityFactory.getAbility(dbStr, card);

newSA.setSVar("ParadigmTrigger", "Mode$ Phase | Phase$ Main1 | ValidPlayer$ You | OptionalDecider$ You | Execute$ ParadigmCopy | TriggerDescription$ Paradigm (" + inst.getReminderText() + ")");
newSA.setSVar("ParadigmCopy", "DB$ Play | Defined$ EffectSource | ValidSA$ Spell | ZoneRegardless$ True | WithoutManaCost$ True | Optional$ True | CopyCard$ True | Paradigm$ True");

saExile.setSubAbility(newSA);

final SpellAbility origSA = card.getFirstSpellAbility();

// append to original SA
origSA.appendSubAbility(saExile);
} else if (keyword.startsWith("Plot")) {
final String[] k = keyword.split(":");
final String manacost = k[1];
Expand Down
1 change: 1 addition & 0 deletions forge-game/src/main/java/forge/game/keyword/Keyword.java
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ public enum Keyword {
OFFERING("Offering", KeywordWithType.class, false, "You may cast this card any time you could cast an instant by sacrificing a %1$s and paying the difference in mana costs between this and the sacrificed %1$s. Mana cost includes color."),
OFFSPRING("Offspring", KeywordWithCost.class, false, "You may pay an additional %s as you cast this spell. If you do, when this creature enters, create a 1/1 token copy of it."),
OVERLOAD("Overload", KeywordWithCost.class, false, "You may cast this spell for its overload cost. If you do, change its text by replacing all instances of \"target\" with \"each.\""),
PARADIGM("Paradigm", SimpleKeyword.class, false, "Then exile this spell. After you first resolve a spell with this name, you may cast a copy of it from exile without paying its mana cost at the beginning of each of your first main phases."),
PARTNER("Partner", Partner.class, true, "You can have two commanders if both have partner."),
PARTNER_WITH("Partner with", KeywordWithType.class, false, "When this creature enters, target player may put %s into their hand from their library, then shuffle."),
PERSIST("Persist", SimpleKeyword.class, false, "When this creature dies, if it had no -1/-1 counters on it, return it to the battlefield under its owner's control with a -1/-1 counter on it."),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -609,14 +609,6 @@ public boolean isCumulativeUpkeep() {
return hasParam("CumulativeUpkeep");
}

public boolean isEpic() {
AbilitySub sub = this.getSubAbility();
while (sub != null && !sub.hasParam("Epic")) {
sub = sub.getSubAbility();
}
return sub != null && sub.hasParam("Epic");
}

public boolean isBargained() {
return isOptionalCostPaid(OptionalCost.Bargain);
}
Expand Down Expand Up @@ -992,7 +984,7 @@ public void resetOnceResolved() {
//resetPaidHash(); // FIXME: if uncommented, breaks Dragon Presence, e.g. Orator of Ojutai + revealing a Dragon from hand.
// Is it truly necessary at this point? The paid hash seems to be reset on all SA instance operations.
// Epic spell keeps original targets
if (!isEpic()) {
if (!this.getHostCard().hasKeyword(Keyword.EPIC)) {
resetTargets();
}
resetTriggeringObjects();
Expand Down
7 changes: 7 additions & 0 deletions forge-gui/res/cardsfolder/upcoming/decorum_dissertation.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Name:Decorum Dissertation
ManaCost:3 B B
Types:Sorcery Lesson
A:SP$ Draw | NumCards$ 2 | ValidTgts$ Player | SubAbility$ DBLoseLife | SpellDescription$ Target player draws two cards and loses 2 life.
SVar:DBLoseLife:DB$ LoseLife | LifeAmount$ 2 | Defined$ Targeted
K:Paradigm
Oracle:Target player draws two cards and loses 2 life.\nParadigm (Then exile this spell. After you first resolve a spell with this name, you may cast a copy of it from exile without paying its mana cost at the beginning of each of your first main phases.)
Loading