Merge pull request #4 from Northmoc/blitz

SNC: Blitz keyword
This commit is contained in:
Agetian
2022-04-12 11:51:27 +03:00
committed by GitHub
11 changed files with 88 additions and 7 deletions

View File

@@ -153,6 +153,8 @@ public class ForgeScript {
} else if (property.equals("hasTapCost")) {
Cost cost = sa.getPayCosts();
return cost != null && cost.hasTapCost();
} else if (property.equals("Blitz")) {
return sa.isBlitz();
} else if (property.equals("Buyback")) {
return sa.isBuyBackAbility();
} else if (property.equals("Cycling")) {

View File

@@ -234,10 +234,10 @@ public class GameAction {
}
}
// Clean up the temporary Dash SVar when the Dashed card leaves the battlefield
// Clean up the temporary Dash/Blitz SVar when the card leaves the battlefield
// Clean up the temporary AtEOT SVar
String endofTurn = c.getSVar("EndOfTurnLeavePlay");
if (fromBattlefield && (endofTurn.equals("Dash") || endofTurn.equals("AtEOT"))) {
if (fromBattlefield && (endofTurn.equals("Dash") || endofTurn.equals("Blitz") || endofTurn.equals("AtEOT"))) {
c.removeSVar("EndOfTurnLeavePlay");
}

View File

@@ -44,18 +44,40 @@ public class CopyPermanentEffect extends TokenEffectBase {
}
final StringBuilder sb = new StringBuilder();
final Player activator = sa.getActivatingPlayer();
final List<Card> tgtCards = getTargetCards(sa);
boolean justOne = tgtCards.size() == 1;
boolean addKWs = sa.hasParam("AddKeywords");
final int numCopies = sa.hasParam("NumCopies") ?
AbilityUtils.calculateAmount(host, sa.getParam("NumCopies"), sa) : 1;
sb.append("Copy ");
sb.append(activator).append(" creates ").append(Lang.nounWithNumeralExceptOne(numCopies, "token");
sb.append(numCopies == 1 ? " that's a copy" : " that are copies").append(" of ");
sb.append(Lang.joinHomogenous(tgtCards));
if (sa.hasParam("AddKeywords")) {
if (addKWs) {
final List<String> keywords = Lists.newArrayList();
keywords.addAll(Arrays.asList(sa.getParam("AddKeywords").split(" & ")));
sb.append(", except ").append(justOne ? "it has " : "they have ");
if (sa.getDescription().contains("except")) {
sb.append(", except ").append(justOne ? "it has " : "they have ");
} else {
sb.append(". ").append(justOne ? "It gains " : "They gain ");
}
sb.append(Lang.joinHomogenous(keywords).toLowerCase());
}
sb.append(".");
if (sa.hasParam("AddTriggers")) {
final String oDesc = sa.getDescription();
final String trigStg = oDesc.substring(oDesc.indexOf("\""),oDesc.lastIndexOf("\"") + 1);
if (addKWs) {
sb.append(" and ").append(trigStg);
} else {
sb.append(". ").append(justOne ? "It gains " : "They gain ").append(trigStg);
}
} else {
sb.append(".");
}
if (sa.hasParam("AtEOT")) {
String atEOT = sa.getParam("AtEOT");
String verb = "Sacrifice ";

View File

@@ -45,6 +45,11 @@ public class PermanentEffect extends SpellAbilityEffect {
c.setSVar("EndOfTurnLeavePlay", "Dash");
registerDelayedTrigger(sa, "Hand", Lists.newArrayList(c));
}
// similar for Blitz keyword
if (sa.isBlitz() && c.isInPlay()) {
c.setSVar("EndOfTurnLeavePlay", "Blitz");
registerDelayedTrigger(sa, "Sacrifice", Lists.newArrayList(c));
}
ZoneType newZone = c.getZone().getZoneType();
if (newZone != previousZone) {

View File

@@ -2160,7 +2160,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|| keyword.startsWith("Transfigure") || keyword.startsWith("Aura swap")
|| keyword.startsWith("Cycling") || keyword.startsWith("TypeCycling")
|| keyword.startsWith("Encore") || keyword.startsWith("Mutate") || keyword.startsWith("Dungeon")
|| keyword.startsWith("Class") || keyword.startsWith("Saga")) {
|| keyword.startsWith("Class") || keyword.startsWith("Saga") || keyword.startsWith("Blitz")) {
// keyword parsing takes care of adding a proper description
} else if (keyword.equals("Unblockable")) {
sbLong.append(getName()).append(" can't be blocked.\r\n");

View File

@@ -2706,6 +2706,26 @@ public class CardFactoryUtil {
sa.setAlternativeCost(AlternativeCost.Bestow);
sa.setIntrinsic(intrinsic);
inst.addSpellAbility(sa);
} else if (keyword.startsWith("Blitz")) {
final String[] k = keyword.split(":");
final Cost blitzCost = new Cost(k[1], false);
final SpellAbility newSA = card.getFirstSpellAbility().copyWithDefinedCost(blitzCost);
final StringBuilder desc = new StringBuilder();
desc.append("Blitz ").append(blitzCost.toSimpleString()).append(" (");
desc.append(inst.getReminderText());
desc.append(")");
newSA.setDescription(desc.toString());
final StringBuilder sb = new StringBuilder();
sb.append(card.getName()).append(" (Blitz)");
newSA.setStackDescription(sb.toString());
newSA.setAlternativeCost(AlternativeCost.Blitz);
newSA.setIntrinsic(intrinsic);
inst.addSpellAbility(newSA);
} else if (keyword.startsWith("Class")) {
final String[] k = keyword.split(":");
final int level = Integer.valueOf(k[1]);
@@ -3455,6 +3475,18 @@ public class CardFactoryUtil {
StaticAbility st = StaticAbility.create(effect, state.getCard(), state, intrinsic);
st.setSVar("AffinityX", "Count$Valid " + t + ".YouCtrl");
inst.addStaticAbility(st);
} else if (keyword.startsWith("Blitz")) {
String effect = "Mode$ Continuous | Affected$ Card.Self+blitzed | AddKeyword$ Haste | AddTrigger$ Dies";
String trig = "Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | " +
"Execute$ TrigDraw | TriggerDescription$ When this creature dies, draw a card.";
String ab = "DB$ Draw | NumCards$ 1";
StaticAbility st = StaticAbility.create(effect, state.getCard(), state, intrinsic);
st.setSVar("Dies", trig);
st.setSVar("TrigDraw", ab);
inst.addStaticAbility(st);
} else if (keyword.equals("Changeling")) {
String effect = "Mode$ Continuous | EffectZone$ All | Affected$ Card.Self" +

View File

@@ -1684,6 +1684,11 @@ public class CardProperty {
return false;
}
return card.getCastSA().isSurged();
} else if (property.equals("blitzed")) {
if (card.getCastSA() == null) {
return false;
}
return card.getCastSA().isBlitz();
} else if (property.equals("dashed")) {
if (card.getCastSA() == null) {
return false;

View File

@@ -31,6 +31,7 @@ public enum Keyword {
BANDING("Banding", SimpleKeyword.class, true, "Any creatures with banding, and up to one without, can attack in a band. Bands are blocked as a group. If any creatures with banding you control are blocking or being blocked by a creature, you divide that creature's combat damage, not its controller, among any of the creatures it's being blocked by or is blocking."),
BATTLE_CRY("Battle cry", SimpleKeyword.class, false, "Whenever this creature attacks, each other attacking creature gets +1/+0 until end of turn."),
BESTOW("Bestow", KeywordWithCost.class, false, "If you cast this card for its bestow cost, it's an Aura spell with enchant creature. It becomes a creature again if it's not attached to a creature."),
BLITZ("Blitz", KeywordWithCost.class, false, "If you cast this spell for its blitz cost, it gains haste and \"When this creature dies, draw a card.\" Sacrifice it at the beginning of the next end step."),
BLOODTHIRST("Bloodthirst", KeywordWithAmount.class, false, "If an opponent was dealt damage this turn, this creature enters the battlefield with {%d:+1/+1 counter} on it."),
BUSHIDO("Bushido", KeywordWithAmount.class, false, "Whenever this creature blocks or becomes blocked, it gets +%1$d/+%1$d until end of turn."),
BUYBACK("Buyback", KeywordWithCost.class, false, "You may pay an additional %s as you cast this spell. If you do, put it into your hand instead of your graveyard as it resolves."),

View File

@@ -3,6 +3,7 @@ package forge.game.spellability;
public enum AlternativeCost {
Awaken,
Bestow,
Blitz,
Cycling, // ActivatedAbility
Dash,
Disturb,

View File

@@ -1424,6 +1424,10 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
return isAlternativeCost(AlternativeCost.Bestow);
}
public final boolean isBlitz() {
return isAlternativeCost(AlternativeCost.Blitz);
}
public final boolean isDash() {
return isAlternativeCost(AlternativeCost.Dash);
}

View File

@@ -0,0 +1,9 @@
Name:Jaxis, the Troublemaker
ManaCost:3 R
Types:Legendary Creature Human Warrior
PT:2/3
A:AB$ CopyPermanent | Cost$ R T Discard<1/Card> | ValidTgts$ Creature.Other+YouCtrl | TgtPrompt$ Select another target creature you control | AddKeywords$ Haste | AddTriggers$ Dies | AddSVars$ TrigDraw | AtEOT$ Sacrifice | SorcerySpeed$ True | SpellDescription$ Create a token that's a copy of another target creature you control. It gains haste and "When this creature dies, draw a card." Sacrifice it at the beginning of the next end step. Activate only as a sorcery.
SVar:Dies:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigDraw | TriggerDescription$ When this creature dies, draw a card.
SVar:TrigDraw:DB$ Draw | NumCards$ 1
K:Blitz:1 R
Oracle:{R}, {T}, Discard a card: Create a token that's a copy of another target creature you control. It gains haste and "When this creature dies, draw a card." Sacrifice it at the beginning of the next end step. Activate only as a sorcery.\nBlitz {1}{R} (If you cast this spell for its blitz cost, it gains haste and "When this creature dies, draw a card." Sacrifice it at the beginning of the next end step.)