From 6cb1fca434b0ec59232d12cb76eba1aab7679ab8 Mon Sep 17 00:00:00 2001
From: swordshine
Date: Sun, 9 Jun 2013 05:20:15 +0000
Subject: [PATCH] - Added Grave Consequences and Psychic Vortex
---
.gitattributes | 2 +
res/cardsfolder/g/grave_consequences.txt | 16 ++
res/cardsfolder/p/psychic_vortex.txt | 10 ++
.../ability/effects/ReorderZoneEffect.java | 4 +-
src/main/java/forge/card/cost/Cost.java | 147 +++++++++---------
.../java/forge/game/player/HumanPlay.java | 16 +-
6 files changed, 118 insertions(+), 77 deletions(-)
create mode 100644 res/cardsfolder/g/grave_consequences.txt
create mode 100644 res/cardsfolder/p/psychic_vortex.txt
diff --git a/.gitattributes b/.gitattributes
index 8a3bf249edf..b85fa61ecd3 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -4565,6 +4565,7 @@ res/cardsfolder/g/grasslands.txt svneol=native#text/plain
res/cardsfolder/g/gratuitous_violence.txt svneol=native#text/plain
res/cardsfolder/g/grave_betrayal.txt -text
res/cardsfolder/g/grave_bramble.txt -text
+res/cardsfolder/g/grave_consequences.txt -text
res/cardsfolder/g/grave_defiler.txt svneol=native#text/plain
res/cardsfolder/g/grave_exchange.txt -text
res/cardsfolder/g/grave_pact.txt svneol=native#text/plain
@@ -8311,6 +8312,7 @@ res/cardsfolder/p/psychic_surgery.txt svneol=native#text/plain
res/cardsfolder/p/psychic_trance.txt -text svneol=unset#text/plain
res/cardsfolder/p/psychic_transfer.txt -text
res/cardsfolder/p/psychic_venom.txt svneol=native#text/plain
+res/cardsfolder/p/psychic_vortex.txt -text
res/cardsfolder/p/psychogenic_probe.txt -text
res/cardsfolder/p/psychosis_crawler.txt svneol=native#text/plain
res/cardsfolder/p/psychotic_episode.txt -text svneol=unset#text/plain
diff --git a/res/cardsfolder/g/grave_consequences.txt b/res/cardsfolder/g/grave_consequences.txt
new file mode 100644
index 00000000000..08c3168eca8
--- /dev/null
+++ b/res/cardsfolder/g/grave_consequences.txt
@@ -0,0 +1,16 @@
+Name:Grave Consequences
+ManaCost:1 B
+Types:Instant
+#AI will exile all cards from its graveyard currently
+A:SP$ RepeatEach | Cost$ 1 B | RepeatPlayers$ Player | RepeatSubAbility$ DBChooseNum | SubAbility$ DBExile | SpellDescription$ Each player may exile any number of cards from his or her graveyard. Then each player loses 1 life for each card in his or her graveyard. Draw a card.
+SVar:DBChooseNum:DB$ ChooseNumber | Defined$ Player.IsRemembered | Min$ 0 | Max$ X | References$ X | ListTitle$ Exile how many cards in your graveyard? | SubAbility$ DBChooseCard
+SVar:DBChooseCard:DB$ ChooseCard | Defined$ Player.IsRemembered | Amount$ Y | References$ Y | Choices$ Card.RememberedPlayerCtrl | ChoiceZone$ Graveyard | Mandatory$ True | RememberChosen$ True
+SVar:DBExile:DB$ ChangeZoneAll | ChangeType$ Card.IsRemembered | Origin$ Graveyard | Destination$ Exile | SubAbility$ DBRepeat
+SVar:DBRepeat:DB$ RepeatEach | RepeatPlayers$ Player | RepeatSubAbility$ DBLoseLife | SubAbility$ DBDraw
+SVar:DBLoseLife:DB$ LoseLife | Defined$ Player.IsRemembered | LifeAmount$ X | References$ X
+SVar:DBDraw:DB$ Draw | NumCards$ 1
+SVar:X:Count$ValidGraveyard Card.RememberedPlayerCtrl
+SVar:Y:Count$ChosenNumber
+SVar:RemAIDeck:True
+SVar:Picture:http://www.wizards.com/global/images/magic/general/grave_consequences.jpg
+Oracle:Each player may exile any number of cards from his or her graveyard. Then each player loses 1 life for each card in his or her graveyard.\nDraw a card.
diff --git a/res/cardsfolder/p/psychic_vortex.txt b/res/cardsfolder/p/psychic_vortex.txt
new file mode 100644
index 00000000000..1ee8ba6fe5d
--- /dev/null
+++ b/res/cardsfolder/p/psychic_vortex.txt
@@ -0,0 +1,10 @@
+Name:Psychic Vortex
+ManaCost:2 U U
+Types:Enchantment
+K:Cumulative upkeep:DrawYou<1>:Draw a card.
+T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | Execute$ TrigSac | TriggerZones$ Battlefield | TriggerDescription$ At the beginning of your end step, sacrifice a land and discard your hand.
+SVar:TrigSac:AB$ Sacrifice | Cost$ 0 | SacValid$ Land | SubAbility$ DBDiscard
+SVar:DBDiscard:DB$ Discard | Mode$ Hand
+SVar:RemAIDeck:True
+SVar:Picture:http://www.wizards.com/global/images/magic/general/psychic_vortex.jpg
+Oracle:Cumulative upkeep-Draw a card. (At the beginning of your upkeep, put an age counter on this permanent, then sacrifice it unless you pay its upkeep cost for each age counter on it.)\nAt the beginning of your end step, sacrifice a land and discard your hand.
diff --git a/src/main/java/forge/card/ability/effects/ReorderZoneEffect.java b/src/main/java/forge/card/ability/effects/ReorderZoneEffect.java
index 1987aa77411..86c500d3be5 100644
--- a/src/main/java/forge/card/ability/effects/ReorderZoneEffect.java
+++ b/src/main/java/forge/card/ability/effects/ReorderZoneEffect.java
@@ -27,7 +27,7 @@ public class ReorderZoneEffect extends SpellAbilityEffect {
final List tgtPlayers = getTargetPlayers(sa);
boolean shuffle = sa.hasParam("Random");
- return "Reorder " + Lang.joinHomogenous(tgtPlayers)+ " " + zone.toString() + " " + (shuffle ? "at random." : "as your choose.");
+ return "Reorder " + Lang.joinHomogenous(tgtPlayers) + " " + zone.toString() + " " + (shuffle ? "at random." : "as your choose.");
}
/**
@@ -36,8 +36,6 @@ public class ReorderZoneEffect extends SpellAbilityEffect {
*
* @param sa
* a {@link forge.card.spellability.SpellAbility} object.
- * @param af
- * a {@link forge.card.ability.AbilityFactory} object.
*/
@Override
diff --git a/src/main/java/forge/card/cost/Cost.java b/src/main/java/forge/card/cost/Cost.java
index a09b55fd9ab..5620df36e57 100644
--- a/src/main/java/forge/card/cost/Cost.java
+++ b/src/main/java/forge/card/cost/Cost.java
@@ -100,7 +100,7 @@ public class Cost {
private Cost(int colorlessmana) {
costParts.add(new CostPartMana(ManaCost.get(colorlessmana), null, false));
}
-
+
// Parsing Strings
public Cost(ManaCost cost, final boolean bAbility) {
@@ -111,8 +111,6 @@ public class Cost {
*
* Constructor for Cost.
*
- * @param card
- * a Card object that the Cost is associated with
* @param parse
* a {@link java.lang.String} object.
* @param bAbility
@@ -127,23 +125,23 @@ public class Cost {
StringBuilder manaParts = new StringBuilder();
String[] parts = TextUtil.splitWithParenthesis(parse, ' ', '<', '>');
-
+
// make this before parse so that classes that need it get data in their constructor
- for(String part : parts) {
- if ( part.equals("T") || part.equals("Tap") )
+ for (String part : parts) {
+ if (part.equals("T") || part.equals("Tap"))
this.tapCost = true;
- if ( part.equals("Q") || part.equals("Untap") )
+ if (part.equals("Q") || part.equals("Untap"))
untapCost = true;
}
-
+
CostPartMana parsedMana = null;
- for(String part : parts) {
- if( "XCantBe0".equals(part) )
+ for (String part : parts) {
+ if ("XCantBe0".equals(part))
xCantBe0 = true;
else {
CostPart cp = parseCostPart(part, tapCost, untapCost);
- if ( null != cp )
- if ( cp instanceof CostPartMana ) {
+ if (null != cp )
+ if (cp instanceof CostPartMana ) {
parsedMana = (CostPartMana) cp;
} else {
this.costParts.add(cp);
@@ -151,28 +149,27 @@ public class Cost {
else
manaParts.append(part).append(" ");
}
-
+
}
- if ( parsedMana == null && manaParts.length() > 0) {
+ if (parsedMana == null && manaParts.length() > 0) {
parsedMana = new CostPartMana(new ManaCost(new ManaCostParser(manaParts.toString())), null, xCantBe0);
}
- if ( parsedMana != null ) {
+ if (parsedMana != null) {
this.costParts.add(0, parsedMana);
}
-
// inspect parts to set Sac, {T} and {Q} flags
for (int iCp = 0; iCp < costParts.size(); iCp++) {
CostPart cp = costParts.get(iCp);
- // my guess why Q/T are to be first and are followed by mana parts
- // is because Q/T are undoable and mana is interactive, so it well be easy to rollback if player refuses to pay
- if( cp instanceof CostUntap ) {
+ // my guess why Q/T are to be first and are followed by mana parts
+ // is because Q/T are undoable and mana is interactive, so it well be easy to rollback if player refuses to pay
+ if (cp instanceof CostUntap) {
costParts.remove(iCp);
costParts.add(0, cp);
}
- if( cp instanceof CostTap ) {
+ if (cp instanceof CostTap) {
costParts.remove(iCp);
costParts.add(0, cp);
}
@@ -181,155 +178,159 @@ public class Cost {
private static CostPart parseCostPart(String parse, boolean tapCost, boolean untapCost) {
- if(parse.startsWith("Mana<")) {
+ if (parse.startsWith("Mana<")) {
final String[] splitStr = TextUtil.split(abCostParse(parse, 1)[0], '\\');
final String restriction = splitStr.length > 1 ? splitStr[1] : null;
final boolean xCantBe0 = splitStr.length > 1 && splitStr[1].equals("XCantBe0");
return new CostPartMana(new ManaCost(new ManaCostParser(splitStr[0])), xCantBe0 ? null : restriction, xCantBe0);
}
-
- if(parse.startsWith("tapXType<")) {
+
+ if (parse.startsWith("tapXType<")) {
final String[] splitStr = abCostParse(parse, 3);
final String description = splitStr.length > 2 ? splitStr[2] : null;
return new CostTapType(splitStr[0], splitStr[1], description, tapCost);
}
-
- if(parse.startsWith("untapYType<")) {
+
+ if (parse.startsWith("untapYType<")) {
final String[] splitStr = abCostParse(parse, 3);
final String description = splitStr.length > 2 ? splitStr[2] : null;
return new CostUntapType(splitStr[0], splitStr[1], description, untapCost);
}
-
- if(parse.startsWith("SubCounter<")) {
+
+ if (parse.startsWith("SubCounter<")) {
// SubCounter
final String[] splitStr = abCostParse(parse, 5);
final String type = splitStr.length > 2 ? splitStr[2] : "CARDNAME";
final String description = splitStr.length > 3 ? splitStr[3] : null;
final ZoneType zone = splitStr.length > 4 ? ZoneType.smartValueOf(splitStr[4]) : ZoneType.Battlefield;
-
+
return new CostRemoveCounter(splitStr[0], CounterType.valueOf(splitStr[1]), type, description, zone);
}
-
- if(parse.startsWith("AddCounter<")) {
+
+ if (parse.startsWith("AddCounter<")) {
// AddCounter
final String[] splitStr = abCostParse(parse, 4);
final String target = splitStr.length > 2 ? splitStr[2] : "CARDNAME";
final String description = splitStr.length > 3 ? splitStr[3] : null;
return new CostPutCounter(splitStr[0], CounterType.valueOf(splitStr[1]), target, description);
}
-
+
// While no card has "PayLife<2> PayLife<3> there might be a card that
// Changes Cost by adding a Life Payment
- if(parse.startsWith("PayLife<")) {
+ if (parse.startsWith("PayLife<")) {
// PayLife
final String[] splitStr = abCostParse(parse, 1);
return new CostPayLife(splitStr[0]);
}
-
- if(parse.startsWith("GainLife<")) {
+
+ if (parse.startsWith("GainLife<")) {
// PayLife
final String[] splitStr = abCostParse(parse, 3);
int cnt = splitStr.length > 2 ? "*".equals(splitStr[2]) ? Integer.MAX_VALUE : Integer.parseInt(splitStr[2]) : 1;
return new CostGainLife(splitStr[0], splitStr[1], cnt);
}
-
- if(parse.startsWith("Unattach<")) {
+
+ if (parse.startsWith("Unattach<")) {
// Unattach
final String[] splitStr = abCostParse(parse, 2);
final String description = splitStr.length > 1 ? splitStr[1] : null;
return new CostUnattach(splitStr[0], description);
- }
+ }
- if(parse.startsWith("DamageYou<")) {
+ if (parse.startsWith("DamageYou<")) {
// Damage
final String[] splitStr = abCostParse(parse, 1);
return new CostDamage(splitStr[0]);
}
-
- if(parse.startsWith("Mill<")) {
+
+ if (parse.startsWith("Mill<")) {
// Mill
final String[] splitStr = abCostParse(parse, 1);
return new CostMill(splitStr[0]);
}
-
- if(parse.startsWith("Discard<")) {
+
+ if (parse.startsWith("Discard<")) {
// Discard
final String[] splitStr = abCostParse(parse, 3);
final String description = splitStr.length > 2 ? splitStr[2] : null;
return new CostDiscard(splitStr[0], splitStr[1], description);
}
-
- if(parse.startsWith("Sac<")) {
+
+ if (parse.startsWith("Sac<")) {
final String[] splitStr = abCostParse(parse, 3);
final String description = splitStr.length > 2 ? splitStr[2] : null;
return new CostSacrifice(splitStr[0], splitStr[1], description);
}
-
- if(parse.startsWith("Exile<")) {
+
+ if (parse.startsWith("Exile<")) {
final String[] splitStr = abCostParse(parse, 3);
final String description = splitStr.length > 2 ? splitStr[2] : null;
return new CostExile(splitStr[0], splitStr[1], description, ZoneType.Battlefield);
}
-
- if(parse.startsWith("ExileFromHand<")) {
+
+ if (parse.startsWith("ExileFromHand<")) {
final String[] splitStr = abCostParse(parse, 3);
final String description = splitStr.length > 2 ? splitStr[2] : null;
return new CostExile(splitStr[0], splitStr[1], description, ZoneType.Hand);
}
-
- if(parse.startsWith("ExileFromGrave<")) {
+
+ if (parse.startsWith("ExileFromGrave<")) {
final String[] splitStr = abCostParse(parse, 3);
final String description = splitStr.length > 2 ? splitStr[2] : null;
return new CostExile(splitStr[0], splitStr[1], description, ZoneType.Graveyard);
}
-
- if(parse.startsWith("ExileFromStack<")) {
+
+ if (parse.startsWith("ExileFromStack<")) {
final String[] splitStr = abCostParse(parse, 3);
final String description = splitStr.length > 2 ? splitStr[2] : null;
return new CostExile(splitStr[0], splitStr[1], description, ZoneType.Stack);
}
-
- if(parse.startsWith("ExileFromTop<")) {
+
+ if (parse.startsWith("ExileFromTop<")) {
final String[] splitStr = abCostParse(parse, 3);
final String description = splitStr.length > 2 ? splitStr[2] : null;
return new CostExile(splitStr[0], splitStr[1], description, ZoneType.Library);
}
-
- if(parse.startsWith("ExileSameGrave<")) {
+
+ if (parse.startsWith("ExileSameGrave<")) {
final String[] splitStr = abCostParse(parse, 3);
final String description = splitStr.length > 2 ? splitStr[2] : null;
return new CostExile(splitStr[0], splitStr[1], description, ZoneType.Graveyard, true);
}
-
- if(parse.equals("ExileAndPay")) {
+
+ if (parse.equals("ExileAndPay")) {
return new CostExileAndPay();
}
-
- if(parse.startsWith("Return<")) {
+
+ if (parse.startsWith("Return<")) {
final String[] splitStr = abCostParse(parse, 3);
final String description = splitStr.length > 2 ? splitStr[2] : null;
return new CostReturn(splitStr[0], splitStr[1], description);
}
-
- if(parse.startsWith("Reveal<")) {
+
+ if (parse.startsWith("Reveal<")) {
final String[] splitStr = abCostParse(parse, 3);
final String description = splitStr.length > 2 ? splitStr[2] : null;
return new CostReveal(splitStr[0], splitStr[1], description);
}
+ if (parse.startsWith("DrawYou<")) {
+ final String[] splitStr = abCostParse(parse, 1);
+ return new CostDraw(splitStr[0], "You");
+ }
- if(parse.startsWith("PutCardToLibFromHand<")) {
+ if (parse.startsWith("PutCardToLibFromHand<")) {
final String[] splitStr = abCostParse(parse, 4);
final String description = splitStr.length > 3 ? splitStr[3] : null;
return new CostPutCardToLib(splitStr[0], splitStr[1], splitStr[2], description, ZoneType.Hand);
}
- if(parse.startsWith("PutCardToLibFromGrave<")) {
+ if (parse.startsWith("PutCardToLibFromGrave<")) {
final String[] splitStr = abCostParse(parse, 4);
final String description = splitStr.length > 3 ? splitStr[3] : null;
return new CostPutCardToLib(splitStr[0], splitStr[1], splitStr[2], description, ZoneType.Graveyard);
}
-
- if(parse.startsWith("PutCardToLibFromSameGrave<")) {
+
+ if (parse.startsWith("PutCardToLibFromSameGrave<")) {
final String[] splitStr = abCostParse(parse, 4);
final String description = splitStr.length > 3 ? splitStr[3] : null;
return new CostPutCardToLib(splitStr[0], splitStr[1], splitStr[2], description, ZoneType.Graveyard, true);
@@ -370,7 +371,7 @@ public class Cost {
public final Cost copyWithNoMana() {
Cost toRet = new Cost(0);
toRet.isAbility = this.isAbility;
- for(CostPart cp : this.costParts) {
+ for (CostPart cp : this.costParts) {
if (!(cp instanceof CostPartMana))
toRet.costParts.add(cp);
}
@@ -434,7 +435,7 @@ public class Cost {
return this.isAbility;
}
-
+
/**
*
* isRenewableResource.
@@ -662,7 +663,7 @@ public class Cost {
return sb.toString();
}
-
+
public Cost add(Cost cost1) {
CostPartMana costPart2 = this.getCostMana();
for (final CostPart part : cost1.getCostParts()) {
@@ -672,16 +673,16 @@ public class Cost {
oldManaCost.combineManaCost(costPart2.getMana());
String r2 = costPart2.getRestiction();
String r1 = ((CostPartMana) part).getRestiction();
- String r = r1 == null ? r2 : ( r2 == null ? r1 : r1+"."+r2);
+ String r = r1 == null ? r2 : ( r2 == null ? r1 : r1 + "." + r2);
getCostParts().remove(costPart2);
getCostParts().add(0, new CostPartMana(oldManaCost.toManaCost(), r, !xCanBe0));
- } else {
+ } else {
getCostParts().add(part);
}
}
return this;
}
-
+
public static int chooseXValue(final Card card, final SpellAbility sa, final int maxValue) {
/*final String chosen = sa.getSVar("ChosenX");
if (chosen.length() > 0) {
@@ -697,6 +698,6 @@ public class Cost {
card.setSVar("ChosenX", Integer.toString(chosenX));
return chosenX;
}
-
+
public static final Cost Zero = new Cost(0);
}
diff --git a/src/main/java/forge/game/player/HumanPlay.java b/src/main/java/forge/game/player/HumanPlay.java
index a1a26b87c4e..2853f608a77 100644
--- a/src/main/java/forge/game/player/HumanPlay.java
+++ b/src/main/java/forge/game/player/HumanPlay.java
@@ -20,6 +20,7 @@ import forge.card.cardfactory.CardFactoryUtil;
import forge.card.cost.Cost;
import forge.card.cost.CostDamage;
import forge.card.cost.CostDiscard;
+import forge.card.cost.CostDraw;
import forge.card.cost.CostExile;
import forge.card.cost.CostMill;
import forge.card.cost.CostPart;
@@ -319,7 +320,20 @@ public class HumanPlay {
p.payLife(amount, null);
}
-
+
+ else if (part instanceof CostDraw) {
+ final int amount = getAmountFromPart(part, source, sourceAbility);
+ if (!p.canDraw()) {
+ return false;
+ }
+
+ if (false == GuiDialog.confirm(source, "Do you want to draw " + amount + " card(s)?" + orString)) {
+ return false;
+ }
+
+ p.drawCards(amount);
+ }
+
else if (part instanceof CostMill) {
final int amount = getAmountFromPart(part, source, sourceAbility);
final List list = p.getCardsIn(ZoneType.Library);