Merge branch 'disturb' into 'master'

MID: add Disturb keyword

See merge request core-developers/forge!5285
This commit is contained in:
Michael Kamensky
2021-09-04 04:14:40 +00:00
8 changed files with 96 additions and 23 deletions

View File

@@ -175,7 +175,29 @@ public final class GameActionUtil {
for (final KeywordInterface inst : source.getKeywords()) {
final String keyword = inst.getOriginal();
if (keyword.startsWith("Escape")) {
if (keyword.startsWith("Disturb")) {
final String[] k = keyword.split(":");
final Cost disturbCost = new Cost(k[1], true);
final SpellAbility newSA = sa.copyWithManaCostReplaced(activator, disturbCost);
newSA.setActivatingPlayer(activator);
newSA.putParam("PrecostDesc", "Disturb —");
newSA.putParam("CostDesc", disturbCost.toString());
// makes new SpellDescription
final StringBuilder desc = new StringBuilder();
desc.append(newSA.getCostDescription());
desc.append("(").append(inst.getReminderText()).append(")");
newSA.setDescription(desc.toString());
newSA.putParam("AfterDescription", "(Disturbed)");
newSA.setAlternativeCost(AlternativeCost.Disturb);
newSA.getRestrictions().setZone(ZoneType.Graveyard);
newSA.setCardState(source.getAlternateState());
alternatives.add(newSA);
} else if (keyword.startsWith("Escape")) {
final String[] k = keyword.split(":");
final Cost escapeCost = new Cost(k[1], true);

View File

@@ -1943,7 +1943,9 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
} else {
sbLong.append(parts[0]).append(" ").append(ManaCostParser.parse(parts[1])).append("\r\n");
}
} else if (keyword.startsWith("Morph") || keyword.startsWith("Megamorph") || keyword.startsWith("Escape") || keyword.startsWith("Foretell:")) {
} else if (keyword.startsWith("Morph") || keyword.startsWith("Megamorph")
|| keyword.startsWith("Escape") || keyword.startsWith("Foretell:")
|| keyword.startsWith("Disturb")) {
String[] k = keyword.split(":");
sbLong.append(k[0]);
if (k.length > 1) {
@@ -2544,7 +2546,8 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
sbBefore.append("\r\n");
} else if (keyword.startsWith("Entwine") || keyword.startsWith("Madness")
|| keyword.startsWith("Miracle") || keyword.startsWith("Recover")
|| keyword.startsWith("Escape") || keyword.startsWith("Foretell:")) {
|| keyword.startsWith("Escape") || keyword.startsWith("Foretell:")
|| keyword.startsWith("Disturb")) {
final String[] k = keyword.split(":");
final Cost cost = new Cost(k[1], false);

View File

@@ -926,8 +926,7 @@ public class CardProperty {
final List<Card> cards = CardUtil.getThisTurnCast("Card", source, spellAbility);
if (cards.size() < 2) {
return false;
}
else if (cards.get(1) != card) {
} else if (cards.get(1) != card) {
return false;
}
} else if (property.equals("ThisTurnCast")) {
@@ -1232,8 +1231,7 @@ public class CardProperty {
if (!cards.contains(card)) {
return false;
}
}
else if (property.startsWith("lowestCMC")) {
} else if (property.startsWith("lowestCMC")) {
final CardCollectionView cards = game.getCardsIn(ZoneType.Battlefield);
for (final Card crd : cards) {
if (!crd.isLand() && !crd.isImmutable()) {
@@ -1369,9 +1367,7 @@ public class CardProperty {
if (!Expressions.compare(y, property, x)) {
return false;
}
}
else if (property.startsWith("ManaCost")) {
} else if (property.startsWith("ManaCost")) {
if (!card.getManaCost().getShortString().equals(property.substring(8))) {
return false;
}
@@ -1471,12 +1467,17 @@ public class CardProperty {
if (combat.isBlocking(card, c)) {
return true;
}
};
}
;
return false;
}
} else if (property.startsWith("sharesBlockingAssignmentWith")) {
if (null == combat) { return false; }
if (null == combat.getAttackersBlockedBy(source) || null == combat.getAttackersBlockedBy(card)) { return false; }
if (null == combat) {
return false;
}
if (null == combat.getAttackersBlockedBy(source) || null == combat.getAttackersBlockedBy(card)) {
return false;
}
CardCollection sourceBlocking = new CardCollection(combat.getAttackersBlockedBy(source));
CardCollection thisBlocking = new CardCollection(combat.getAttackersBlockedBy(card));
@@ -1512,7 +1513,8 @@ public class CardProperty {
if (blocked.contains(c)) {
return true;
}
};
}
;
return false;
} else if (property.startsWith("blockedByValidThisTurn ")) {
CardCollectionView blocked = card.getBlockedByThisTurn();
@@ -1527,7 +1529,8 @@ public class CardProperty {
if (blocked.contains(c)) {
return true;
}
};
}
;
return false;
} else if (property.startsWith("blockedBySourceThisTurn")) {
return source.getBlockedByThisTurn().contains(card);

View File

@@ -53,6 +53,7 @@ public enum Keyword {
DETHRONE("Dethrone", SimpleKeyword.class, false, "Whenever this creature attacks the player with the most life or tied for the most life, put a +1/+1 counter on it."),
DEVOUR("Devour", KeywordWithAmount.class, false, "As this creature enters the battlefield, you may sacrifice any number of creatures. This creature enters the battlefield with {%d:+1/+1 counter} on it for each creature sacrificed this way."),
DEVOID("Devoid", SimpleKeyword.class, true, "This card has no color."),
DISTURB("Disturb", KeywordWithCost.class, false, "You may cast this card from your graveyard transformed for its disturb cost."),
DOUBLE_STRIKE("Double Strike", SimpleKeyword.class, true, "This creature deals both first-strike and regular combat damage."),
DREDGE("Dredge", KeywordWithAmount.class, false, "If you would draw a card, instead you may put exactly {%d:card} from the top of your library into your graveyard. If you do, return this card from your graveyard to your hand. Otherwise, draw a card."),
ECHO("Echo", KeywordWithCost.class, false, "At the beginning of your upkeep, if this permanent came under your control since the beginning of your last upkeep, sacrifice it unless you pay %s."),

View File

@@ -5,6 +5,7 @@ public enum AlternativeCost {
Bestow,
Cycling, // ActivatedAbility
Dash,
Disturb,
Emerge,
Escape,
Evoke,

View File

@@ -1370,6 +1370,10 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
return isAlternativeCost(AlternativeCost.Dash);
}
public final boolean isDisturb() {
return isAlternativeCost(AlternativeCost.Disturb);
}
public final boolean isEscape() {
return isAlternativeCost(AlternativeCost.Escape);
}

View File

@@ -0,0 +1,19 @@
Name:Baithook Angler
ManaCost:1 U
Types:Creature Human Peasant
PT:2/1
K:Disturb:1 U
AlternateMode:DoubleFaced
Oracle:Disturb {1}{U} (You may cast this card from your graveyard transformed for its disturb cost.)
ALTERNATE
Name:Hook-Haunt Drifter
ManaCost:no cost
Types:Creature Spirit
Colors:blue
PT:1/2
K:Flying
R:Event$ Moved | ValidCard$ Card.Self | Destination$ Graveyard | ReplaceWith$ Exile | Description$ If CARDNAME would be put into a graveyard from anywhere, exile it instead.
SVar:Exile:DB$ ChangeZone | Hidden$ True | Origin$ All | Destination$ Exile | Defined$ ReplacedCard
Oracle:Flying\nIf Hook-Haunt Drifter would be put into a graveyard from anywhere, exile it instead.

View File

@@ -0,0 +1,20 @@
Name:Beloved Beggar
ManaCost:1 W
Types:Creature Human Peasant
PT:0/4
K:Disturb:4 W W
AlternateMode:DoubleFaced
Oracle:Disturb {4}{W}{W} (You may cast this card from your graveyard transformed for its disturb cost.)
ALTERNATE
Name:Generous Soul
ManaCost:no cost
Types:Creature Spirit
Colors:white
PT:4/4
K:Flying
K:Vigilance
R:Event$ Moved | ValidCard$ Card.Self | Destination$ Graveyard | ReplaceWith$ Exile | Description$ If CARDNAME would be put into a graveyard from anywhere, exile it instead.
SVar:Exile:DB$ ChangeZone | Hidden$ True | Origin$ All | Destination$ Exile | Defined$ ReplacedCard
Oracle:Flying, vigilance\nIf Generous Soul would be put into a graveyard from anywhere, exile it instead.