diff --git a/.gitattributes b/.gitattributes
index 9fdac59a5fc..c473a165000 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -3311,6 +3311,7 @@ res/cardsfolder/f/flameborn_hellion.txt svneol=native#text/plain
res/cardsfolder/f/flameborn_viron.txt svneol=native#text/plain
res/cardsfolder/f/flamebreak.txt svneol=native#text/plain
res/cardsfolder/f/flamecore_elemental.txt svneol=native#text/plain
+res/cardsfolder/f/flamekin_bladewhirl.txt -text
res/cardsfolder/f/flamekin_brawler.txt svneol=native#text/plain
res/cardsfolder/f/flamekin_harbinger.txt svneol=native#text/plain
res/cardsfolder/f/flamekin_spitfire.txt svneol=native#text/plain
diff --git a/res/cardsfolder/f/flamekin_bladewhirl.txt b/res/cardsfolder/f/flamekin_bladewhirl.txt
new file mode 100644
index 00000000000..5c442f641bd
--- /dev/null
+++ b/res/cardsfolder/f/flamekin_bladewhirl.txt
@@ -0,0 +1,11 @@
+Name:Flamekin Bladewhirl
+ManaCost:R
+Types:Creature Elemental Warrior
+Text:As an additional cost to cast Flamekin Bladewhirl, reveal an Elemental card from your hand or pay 3.
+PT:2/1
+K:AlternateAdditionalCost:Reveal<1/Elemental>:3
+SVar:Rarity:Uncommon
+SVar:Picture:http://www.wizards.com/global/images/magic/general/flamekin_bladewhirl.jpg
+SetInfo:LRW|Uncommon|http://magiccards.info/scans/en/lw/165.jpg
+Oracle:As an additional cost to cast Flamekin Bladewhirl, reveal an Elemental card from your hand or pay {3}.
+End
\ No newline at end of file
diff --git a/res/preferences/editor.preferences b/res/preferences/editor.preferences
index 551bce40aff..7569c1ca63b 100644
--- a/res/preferences/editor.preferences
+++ b/res/preferences/editor.preferences
@@ -1,32 +1,32 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/forge/Card.java b/src/main/java/forge/Card.java
index 0024f120589..95f03cdb2e3 100644
--- a/src/main/java/forge/Card.java
+++ b/src/main/java/forge/Card.java
@@ -2179,192 +2179,195 @@ public class Card extends GameEntity implements Comparable {
* keywordsToText.
*
*
- * @param keyword
+ * @param keywords
* a {@link java.util.ArrayList} object.
* @return a {@link java.lang.String} object.
*/
- public final String keywordsToText(final ArrayList keyword) {
+ public final String keywordsToText(final ArrayList keywords) {
final StringBuilder sb = new StringBuilder();
final StringBuilder sbLong = new StringBuilder();
final StringBuilder sbMana = new StringBuilder();
- for (int i = 0; i < keyword.size(); i++) {
- if (!keyword.get(i).toString().startsWith("Permanents don't untap during their controllers' untap steps")
- && !keyword.get(i).toString().startsWith("PreventAllDamageBy")
- && !keyword.get(i).toString().startsWith("CantBlock")
- && !keyword.get(i).toString().startsWith("CantBeBlockedBy")) {
- if (keyword.get(i).toString().startsWith("CostChange")) {
- final String[] k = keyword.get(i).split(":");
- if (k.length > 8) {
- sbLong.append(k[8]).append("\r\n");
- }
- } else if (keyword.get(i).toString().startsWith("AdjustLandPlays")) {
- final String[] k = keyword.get(i).split(":");
- if (k.length > 3) {
- sbLong.append(k[3]).append("\r\n");
- }
- } else if (keyword.get(i).toString().startsWith("etbCounter")) {
- final String[] p = keyword.get(i).split(":");
- final StringBuilder s = new StringBuilder();
- if (p.length > 4) {
- s.append(p[4]);
- } else {
- final Counters counter = Counters.valueOf(p[1]);
- final String numCounters = p[2];
- s.append(this.getName());
- s.append(" enters the battlefield with ");
- s.append(numCounters);
- s.append(" ");
- s.append(counter.getName());
- s.append(" counter");
- if ("1" != numCounters) {
- s.append("s");
- }
- s.append(" on it.");
- }
- sbLong.append(s).append("\r\n");
- } else if (keyword.get(i).toString().startsWith("Protection:")) {
- final String[] k = keyword.get(i).split(":");
- sbLong.append(k[2]).append("\r\n");
- } else if (keyword.get(i).toString().startsWith("Creatures can't attack unless their controller pays")) {
- final String[] k = keyword.get(i).split(":");
- if (!k[3].equals("no text")) {
- sbLong.append(k[3]).append("\r\n");
- }
- } else if (keyword.get(i).startsWith("Enchant")) {
- String k = keyword.get(i);
- k = k.replace("Curse", "");
- sbLong.append(k).append("\r\n");
- } else if (keyword.get(i).startsWith("Soulshift") || keyword.get(i).startsWith("Devour")
- || keyword.get(i).startsWith("Fading")
- || keyword.get(i).startsWith("Ripple") || keyword.get(i).startsWith("Unearth")
- || keyword.get(i).startsWith("Vanishing") || keyword.get(i).startsWith("Madness")) {
- String k = keyword.get(i);
- k = k.replace(":", " ");
- sbLong.append(k).append("\r\n");
- } else if (keyword.get(i).startsWith("Morph")) {
- sbLong.append("Morph");
- if (keyword.get(i).contains(":")) {
- final Cost mCost = new Cost(this, keyword.get(i).substring(6), true);
- if (!mCost.isOnlyManaCost()) {
- sbLong.append(" -");
- }
- sbLong.append(" ").append(mCost.toString()).delete(sbLong.length() - 2, sbLong.length());
- if (!mCost.isOnlyManaCost()) {
- sbLong.append(".");
- }
- sbLong.append("\r\n");
- }
- } else if (keyword.get(i).startsWith("Echo")) {
- sbLong.append("Echo ");
- final String[] upkeepCostParams = keyword.get(i).split(":");
- final String cost = upkeepCostParams[1];
- final String costDesc = upkeepCostParams.length > 2 ? "- " + upkeepCostParams[2] : cost;
- sbLong.append(costDesc);
- sbLong.append("\r\n");
- } else if (keyword.get(i).startsWith("Cumulative upkeep")) {
- sbLong.append("Cumulative upkeep ");
- final String[] upkeepCostParams = keyword.get(i).split(":");
- final String cost = upkeepCostParams[1];
- final String costDesc = upkeepCostParams.length > 2 ? "- " + upkeepCostParams[2] : cost;
- sbLong.append(costDesc);
- sbLong.append("\r\n");
- } else if (keyword.get(i).startsWith("Amplify")) {
- sbLong.append("Amplify ");
- final String[] ampParams = keyword.get(i).split(":");
- final String magnitude = ampParams[1];
- sbLong.append(magnitude);
- sbLong.append("(As this creature enters the battlefield, put a +1/+1 counter on it for each ");
- sbLong.append(ampParams[2].replace(",", " and/or ")).append(" card you reveal in your hand.)");
- sbLong.append("\r\n");
- } else if (keyword.get(i).startsWith("Alternative Cost")) {
- sbLong.append("Has alternative cost.");
- } else if (keyword.get(i).startsWith("Kicker")) {
- final Cost cost = new Cost(this, keyword.get(i).substring(7), false);
- sbLong.append("Kicker " + cost.toSimpleString() + "\r\n");
- } else if (keyword.get(i).startsWith("Champion")) {
- final String k = this.getKeyword().get(i);
- final String[] kk = k.split(":");
- String types = kk[1];
- if (kk.length > 2) {
- types = kk[2];
- }
- if (kk[1].equals("Creature")) {
- kk[1] = kk[1].toLowerCase();
- }
- sbLong.append("Champion a");
- if (kk[1].toLowerCase().startsWith("a") || kk[1].toLowerCase().startsWith("e")
- || kk[1].toLowerCase().startsWith("i") || kk[1].toLowerCase().startsWith("o")
- || kk[1].toLowerCase().startsWith("u")) {
- sbLong.append("n");
- }
- sbLong.append(" ").append(types);
- sbLong.append(" (When this enters the battlefield, sacrifice it unless you exile another ");
- sbLong.append(types);
- sbLong.append(" you control. When this leaves the battlefield, ");
- sbLong.append("that card returns to the battlefield.)\r\n");
- } else if (keyword.get(i).endsWith(".") && !keyword.get(i).startsWith("Haunt")) {
- sbLong.append(keyword.get(i).toString()).append("\r\n");
- } else if (keyword.get(i).contains("At the beginning of your upkeep, ")
- && keyword.get(i).contains(" unless you pay")) {
- sbLong.append(keyword.get(i).toString()).append("\r\n");
- } else if (keyword.get(i).toString().contains("tap: add ")) {
- sbMana.append(keyword.get(i).toString()).append("\r\n");
- } else if (keyword.get(i).contains("Bloodthirst")) {
- final String k = keyword.get(i);
- final String[] kk = k.split(" ");
- sbLong.append(keyword.get(i)).append(
- " (If an opponent was dealt damage this turn, this creature enters the battlefield with ");
- sbLong.append(kk[1]).append(" +1/+1 counter");
- if (kk[1].equals("X")) {
- sbLong.append("s on it, where X is the damage dealt to your opponents this turn.)");
- sbLong.append("\r\n");
- } else {
- if (Integer.parseInt(kk[1]) > 1) {
- sbLong.append("s");
- }
- sbLong.append(" on it.)").append("\r\n");
- }
- } else if (keyword.get(i).startsWith("Modular")) {
- continue;
- } else if (keyword.get(i).startsWith("Provoke")) {
- sbLong.append(keyword.get(i));
- sbLong.append(" (When this attacks, you may have target creature ");
- sbLong.append("defending player controls untap and block it if able.)");
- } else if (keyword.get(i).startsWith("MayEffectFromOpeningHand")) {
- continue;
- } else if (keyword.get(i).startsWith("ETBReplacement")) {
- continue;
- } else if (keyword.get(i).contains("Haunt")) {
- sb.append("\r\nHaunt (");
- if (this.isCreature()) {
- sb.append("When this creature dies, exile it haunting target creature.");
- } else {
- sb.append("When this spell card is put into a graveyard after resolving, ");
- sb.append("exile it haunting target creature.");
- }
- sb.append(")");
- continue;
- } else if (keyword.get(i).equals("Convoke")) {
- if (sb.length() != 0) {
- sb.append("\r\n");
- }
- sb.append("Convoke (Each creature you tap while casting this spell reduces its cost by 1 or by one mana of that creature's color.)");
- } else if (keyword.get(i).startsWith("Soulbond")) {
- sbLong.append(keyword.get(i));
- sbLong.append(" (You may pair this creature ");
- sbLong.append("with another unpaired creature when either ");
- sbLong.append("enters the battlefield. They remain paired for ");
- sbLong.append("as long as you control both of them)");
- } else if (keyword.get(i).startsWith("Equip")) {
- // keyword parsing takes care of adding a proper description
- continue;
- } else {
- if ((i != 0) && (sb.length() != 0)) {
- sb.append(", ");
- }
- sb.append(keyword.get(i).toString());
+ for (int i = 0; i < keywords.size(); i++) {
+ String keyword = keywords.get(i).toString();
+ if (keyword.startsWith("Permanents don't untap during their controllers' untap steps")
+ || keyword.startsWith("PreventAllDamageBy")
+ || keyword.startsWith("CantBlock")
+ || keyword.startsWith("CantBeBlockedBy")
+ || keyword.startsWith("AlternateAdditionalCost")) {
+ continue;
+ }
+ if (keyword.startsWith("CostChange")) {
+ final String[] k = keywords.get(i).split(":");
+ if (k.length > 8) {
+ sbLong.append(k[8]).append("\r\n");
}
+ } else if (keyword.startsWith("AdjustLandPlays")) {
+ final String[] k = keywords.get(i).split(":");
+ if (k.length > 3) {
+ sbLong.append(k[3]).append("\r\n");
+ }
+ } else if (keyword.startsWith("etbCounter")) {
+ final String[] p = keywords.get(i).split(":");
+ final StringBuilder s = new StringBuilder();
+ if (p.length > 4) {
+ s.append(p[4]);
+ } else {
+ final Counters counter = Counters.valueOf(p[1]);
+ final String numCounters = p[2];
+ s.append(this.getName());
+ s.append(" enters the battlefield with ");
+ s.append(numCounters);
+ s.append(" ");
+ s.append(counter.getName());
+ s.append(" counter");
+ if ("1" != numCounters) {
+ s.append("s");
+ }
+ s.append(" on it.");
+ }
+ sbLong.append(s).append("\r\n");
+ } else if (keyword.startsWith("Protection:")) {
+ final String[] k = keywords.get(i).split(":");
+ sbLong.append(k[2]).append("\r\n");
+ } else if (keyword.startsWith("Creatures can't attack unless their controller pays")) {
+ final String[] k = keywords.get(i).split(":");
+ if (!k[3].equals("no text")) {
+ sbLong.append(k[3]).append("\r\n");
+ }
+ } else if (keyword.startsWith("Enchant")) {
+ String k = keywords.get(i);
+ k = k.replace("Curse", "");
+ sbLong.append(k).append("\r\n");
+ } else if (keyword.startsWith("Soulshift") || keywords.get(i).startsWith("Devour")
+ || keyword.startsWith("Fading")
+ || keyword.startsWith("Ripple") || keywords.get(i).startsWith("Unearth")
+ || keyword.startsWith("Vanishing") || keywords.get(i).startsWith("Madness")) {
+ String k = keywords.get(i);
+ k = k.replace(":", " ");
+ sbLong.append(k).append("\r\n");
+ } else if (keyword.startsWith("Morph")) {
+ sbLong.append("Morph");
+ if (keyword.contains(":")) {
+ final Cost mCost = new Cost(this, keywords.get(i).substring(6), true);
+ if (!mCost.isOnlyManaCost()) {
+ sbLong.append(" -");
+ }
+ sbLong.append(" ").append(mCost.toString()).delete(sbLong.length() - 2, sbLong.length());
+ if (!mCost.isOnlyManaCost()) {
+ sbLong.append(".");
+ }
+ sbLong.append("\r\n");
+ }
+ } else if (keyword.startsWith("Echo")) {
+ sbLong.append("Echo ");
+ final String[] upkeepCostParams = keywords.get(i).split(":");
+ final String cost = upkeepCostParams[1];
+ final String costDesc = upkeepCostParams.length > 2 ? "- " + upkeepCostParams[2] : cost;
+ sbLong.append(costDesc);
+ sbLong.append("\r\n");
+ } else if (keyword.startsWith("Cumulative upkeep")) {
+ sbLong.append("Cumulative upkeep ");
+ final String[] upkeepCostParams = keywords.get(i).split(":");
+ final String cost = upkeepCostParams[1];
+ final String costDesc = upkeepCostParams.length > 2 ? "- " + upkeepCostParams[2] : cost;
+ sbLong.append(costDesc);
+ sbLong.append("\r\n");
+ } else if (keyword.startsWith("Amplify")) {
+ sbLong.append("Amplify ");
+ final String[] ampParams = keywords.get(i).split(":");
+ final String magnitude = ampParams[1];
+ sbLong.append(magnitude);
+ sbLong.append("(As this creature enters the battlefield, put a +1/+1 counter on it for each ");
+ sbLong.append(ampParams[2].replace(",", " and/or ")).append(" card you reveal in your hand.)");
+ sbLong.append("\r\n");
+ } else if (keyword.startsWith("Alternative Cost")) {
+ sbLong.append("Has alternative cost.");
+ } else if (keyword.startsWith("Kicker")) {
+ final Cost cost = new Cost(this, keywords.get(i).substring(7), false);
+ sbLong.append("Kicker " + cost.toSimpleString() + "\r\n");
+ } else if (keyword.startsWith("Champion")) {
+ final String k = this.getKeyword().get(i);
+ final String[] kk = k.split(":");
+ String types = kk[1];
+ if (kk.length > 2) {
+ types = kk[2];
+ }
+ if (kk[1].equals("Creature")) {
+ kk[1] = kk[1].toLowerCase();
+ }
+ sbLong.append("Champion a");
+ if (kk[1].toLowerCase().startsWith("a") || kk[1].toLowerCase().startsWith("e")
+ || kk[1].toLowerCase().startsWith("i") || kk[1].toLowerCase().startsWith("o")
+ || kk[1].toLowerCase().startsWith("u")) {
+ sbLong.append("n");
+ }
+ sbLong.append(" ").append(types);
+ sbLong.append(" (When this enters the battlefield, sacrifice it unless you exile another ");
+ sbLong.append(types);
+ sbLong.append(" you control. When this leaves the battlefield, ");
+ sbLong.append("that card returns to the battlefield.)\r\n");
+ } else if (keyword.endsWith(".") && !keywords.get(i).startsWith("Haunt")) {
+ sbLong.append(keywords.get(i).toString()).append("\r\n");
+ } else if (keyword.contains("At the beginning of your upkeep, ")
+ && keyword.contains(" unless you pay")) {
+ sbLong.append(keywords.get(i).toString()).append("\r\n");
+ } else if (keyword.toString().contains("tap: add ")) {
+ sbMana.append(keywords.get(i).toString()).append("\r\n");
+ } else if (keyword.contains("Bloodthirst")) {
+ final String k = keywords.get(i);
+ final String[] kk = k.split(" ");
+ sbLong.append(keywords.get(i)).append(
+ " (If an opponent was dealt damage this turn, this creature enters the battlefield with ");
+ sbLong.append(kk[1]).append(" +1/+1 counter");
+ if (kk[1].equals("X")) {
+ sbLong.append("s on it, where X is the damage dealt to your opponents this turn.)");
+ sbLong.append("\r\n");
+ } else {
+ if (Integer.parseInt(kk[1]) > 1) {
+ sbLong.append("s");
+ }
+ sbLong.append(" on it.)").append("\r\n");
+ }
+ } else if (keyword.startsWith("Modular")) {
+ continue;
+ } else if (keyword.startsWith("Provoke")) {
+ sbLong.append(keywords.get(i));
+ sbLong.append(" (When this attacks, you may have target creature ");
+ sbLong.append("defending player controls untap and block it if able.)");
+ } else if (keyword.startsWith("MayEffectFromOpeningHand")) {
+ continue;
+ } else if (keyword.startsWith("ETBReplacement")) {
+ continue;
+ } else if (keyword.contains("Haunt")) {
+ sb.append("\r\nHaunt (");
+ if (this.isCreature()) {
+ sb.append("When this creature dies, exile it haunting target creature.");
+ } else {
+ sb.append("When this spell card is put into a graveyard after resolving, ");
+ sb.append("exile it haunting target creature.");
+ }
+ sb.append(")");
+ continue;
+ } else if (keyword.equals("Convoke")) {
+ if (sb.length() != 0) {
+ sb.append("\r\n");
+ }
+ sb.append("Convoke (Each creature you tap while casting this spell reduces its cost by 1 or by one mana of that creature's color.)");
+ } else if (keyword.startsWith("Soulbond")) {
+ sbLong.append(keywords.get(i));
+ sbLong.append(" (You may pair this creature ");
+ sbLong.append("with another unpaired creature when either ");
+ sbLong.append("enters the battlefield. They remain paired for ");
+ sbLong.append("as long as you control both of them)");
+ } else if (keyword.startsWith("Equip")) {
+ // keyword parsing takes care of adding a proper description
+ continue;
+ } else {
+ if ((i != 0) && (sb.length() != 0)) {
+ sb.append(", ");
+ }
+ sb.append(keyword);
}
}
if (sb.length() > 0) {
diff --git a/src/main/java/forge/GameActionUtil.java b/src/main/java/forge/GameActionUtil.java
index 2f6524892b3..6179e1411c7 100644
--- a/src/main/java/forge/GameActionUtil.java
+++ b/src/main/java/forge/GameActionUtil.java
@@ -43,7 +43,6 @@ import forge.card.spellability.SpellAbility;
import forge.card.spellability.SpellAbilityRestriction;
import forge.control.input.InputPayDiscardCost;
import forge.control.input.InputPayManaCostAbility;
-import forge.control.input.InputPayManaCostUtil;
import forge.control.input.InputPayReturnCost;
import forge.control.input.InputPaySacCost;
import forge.game.GameLossReason;
@@ -1819,6 +1818,39 @@ public final class GameActionUtil {
}
abilities.addAll(0, newAbilities);
newAbilities.clear();
+ } else if (keyword.startsWith("AlternateAdditionalCost")) {
+ String costString1 = keyword.split(":")[1];
+ String costString2 = keyword.split(":")[2];
+ for (SpellAbility sa : abilities) {
+ final SpellAbility newSA = sa.copy();
+ newSA.setBasicSpell(false);
+ newSA.setPayCosts(GameActionUtil.combineCosts(newSA, costString1));
+ newSA.setManaCost("");
+ final Cost cost1 = new Cost(source, costString1, false);
+ newSA.setDescription(sa.getDescription() + " (Additional cost " + cost1.toSimpleString() + ")");
+ ArrayList newoacs = new ArrayList();
+ newoacs.addAll(sa.getOptionalAdditionalCosts());
+ newSA.setOptionalAdditionalCosts(newoacs);
+ if (newSA.canPlay()) {
+ newAbilities.add(newAbilities.size(), newSA);
+ }
+ //second option
+ final SpellAbility newSA2 = sa.copy();
+ newSA2.setBasicSpell(false);
+ newSA2.setPayCosts(GameActionUtil.combineCosts(newSA2, costString2));
+ newSA2.setManaCost("");
+ final Cost cost2 = new Cost(source, costString2, false);
+ newSA2.setDescription(sa.getDescription() + " (Additional cost " + cost2.toSimpleString() + ")");
+ ArrayList newoacs2 = new ArrayList();
+ newoacs.addAll(sa.getOptionalAdditionalCosts());
+ newSA2.setOptionalAdditionalCosts(newoacs2);
+ if (newSA2.canPlay()) {
+ newAbilities.add(newAbilities.size(), newSA2);
+ }
+ }
+ abilities.clear();
+ abilities.addAll(0, newAbilities);
+ newAbilities.clear();
}
}
diff --git a/src/main/java/forge/card/cost/CostReveal.java b/src/main/java/forge/card/cost/CostReveal.java
index b52b96516c7..41d4712a415 100644
--- a/src/main/java/forge/card/cost/CostReveal.java
+++ b/src/main/java/forge/card/cost/CostReveal.java
@@ -253,9 +253,9 @@ public class CostReveal extends CostPartWithList {
this.done();
}
- if (handList.size() + this.nReveal < nNeeded) {
+ /*if (handList.size() + this.nReveal < nNeeded) {
this.stop();
- }
+ }*/
final StringBuilder type = new StringBuilder("");
if (!discType.equals("Card")) {
type.append(" ").append(discType);