diff --git a/.gitattributes b/.gitattributes index 5ecd669d7cc..5a1268029bd 100644 --- a/.gitattributes +++ b/.gitattributes @@ -8725,6 +8725,7 @@ forge-gui/res/cardsfolder/p/primal_order.txt svneol=native#text/plain forge-gui/res/cardsfolder/p/primal_plasma.txt svneol=native#text/plain forge-gui/res/cardsfolder/p/primal_rage.txt svneol=native#text/plain forge-gui/res/cardsfolder/p/primal_surge.txt -text +forge-gui/res/cardsfolder/p/primal_vigor.txt -text forge-gui/res/cardsfolder/p/primal_visitation.txt -text forge-gui/res/cardsfolder/p/primal_whisperer.txt svneol=native#text/plain forge-gui/res/cardsfolder/p/primalcrux.txt svneol=native#text/plain @@ -15101,6 +15102,7 @@ forge-gui/src/main/java/forge/game/player/PlayerStatistics.java -text forge-gui/src/main/java/forge/game/player/PlayerType.java svneol=native#text/plain forge-gui/src/main/java/forge/game/player/RegisteredPlayer.java -text forge-gui/src/main/java/forge/game/player/package-info.java svneol=native#text/plain +forge-gui/src/main/java/forge/game/replacement/ReplaceAddCounter.java -text forge-gui/src/main/java/forge/game/replacement/ReplaceCounter.java -text forge-gui/src/main/java/forge/game/replacement/ReplaceDamage.java -text forge-gui/src/main/java/forge/game/replacement/ReplaceDestroy.java -text diff --git a/forge-gui/res/cardsfolder/c/corpsejack_menace.txt b/forge-gui/res/cardsfolder/c/corpsejack_menace.txt index 0972df99299..eff196aafdb 100644 --- a/forge-gui/res/cardsfolder/c/corpsejack_menace.txt +++ b/forge-gui/res/cardsfolder/c/corpsejack_menace.txt @@ -1,7 +1,9 @@ Name:Corpsejack Menace ManaCost:2 B G Types:Creature Fungus -Text:If one or more +1/+1 counters would be placed on a creature you control, twice that many +1/+1 counters are placed on it instead. PT:4/4 +R:Event$ AddCounter | ActiveZones$ Battlefield | ValidCard$ Creature.YouCtrl | ValidCounterType$ P1P1 | ReplaceWith$ AddDoubleCounters | Description$ If one or more +1/+1 counters would be placed on a creature you control, twice that many +1/+1 counters are placed on it instead. +SVar:AddDoubleCounters:DB$ PutCounter | Defined$ ReplacedCard | CounterType$ ReplacedCounterType | CounterNum$ X | References$ X +SVar:X:ReplaceCount$CounterNum/Twice SVar:Picture:http://www.wizards.com/global/images/magic/general/corpsejack_menace.jpg Oracle:If one or more +1/+1 counters would be placed on a creature you control, twice that many +1/+1 counters are placed on it instead. \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/d/doubling_season.txt b/forge-gui/res/cardsfolder/d/doubling_season.txt index fc159c8380e..f21c64d7b1f 100644 --- a/forge-gui/res/cardsfolder/d/doubling_season.txt +++ b/forge-gui/res/cardsfolder/d/doubling_season.txt @@ -1,6 +1,9 @@ Name:Doubling Season ManaCost:4 G Types:Enchantment -Text:If an effect would put one or more tokens onto the battlefield under your control, it puts twice that many of those tokens onto the battlefield instead.\r\nIf an effect would place one or more counters on a permanent you control, it places twice that many of those counters on that permanent instead. +Text:If an effect would put one or more tokens onto the battlefield under your control, it puts twice that many of those tokens onto the battlefield instead. +R:Event$ AddCounter | ActiveZones$ Battlefield | ValidCard$ Permanent.YouCtrl | EffectOnly$ True | ReplaceWith$ AddDoubleCounters | Description$ If an effect would place one or more counters on a permanent you control, it places twice that many of those counters on that permanent instead. +SVar:AddDoubleCounters:DB$ PutCounter | Defined$ ReplacedCard | CounterType$ ReplacedCounterType | CounterNum$ X | References$ X +SVar:X:ReplaceCount$CounterNum/Twice SVar:Picture:http://www.wizards.com/global/images/magic/general/doubling_season.jpg Oracle:If an effect would put one or more tokens onto the battlefield under your control, it puts twice that many of those tokens onto the battlefield instead.\nIf an effect would place one or more counters on a permanent you control, it places twice that many of those counters on that permanent instead. \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/p/primal_vigor.txt b/forge-gui/res/cardsfolder/p/primal_vigor.txt new file mode 100644 index 00000000000..fe5642a3dde --- /dev/null +++ b/forge-gui/res/cardsfolder/p/primal_vigor.txt @@ -0,0 +1,9 @@ +Name:Primal Vigor +ManaCost:4 G +Types:Enchantment +Text:If one or more tokens would be put onto the battlefield, twice that many of those tokens are put onto the battlefield instead. +R:Event$ AddCounter | ActiveZones$ Battlefield | ValidCard$ Creature | ValidCounterType$ P1P1 | ReplaceWith$ AddDoubleP1P1Counters | Description$ If one or more +1/+1 counters would be placed on a creature, twice that many +1/+1 counters are placed on that creature instead. +SVar:AddDoubleP1P1Counters:DB$ PutCounter | Defined$ ReplacedCard | CounterType$ ReplacedCounterType | CounterNum$ X | References$ X +SVar:X:ReplaceCount$CounterNum/Twice +SVar:Picture:http://www.wizards.com/global/images/magic/general/primal_vigor.jpg +Oracle:If one or more tokens would be put onto the battlefield, twice that many of those tokens are put onto the battlefield instead.\nIf one or more +1/+1 counters would be placed on a creature, twice that many +1/+1 counters are placed on that creature instead. diff --git a/forge-gui/res/cardsfolder/s/selesnya_loft_gardens.txt b/forge-gui/res/cardsfolder/s/selesnya_loft_gardens.txt index 9fb9a1cb6df..cca0916e4a6 100644 --- a/forge-gui/res/cardsfolder/s/selesnya_loft_gardens.txt +++ b/forge-gui/res/cardsfolder/s/selesnya_loft_gardens.txt @@ -1,7 +1,10 @@ Name:Selesnya Loft Gardens ManaCost:no cost Types:Plane Ravnica -Text:If an effect would put one or more tokens onto the battlefield, it puts twice that many of those tokens onto the battlefield instead.\r\nIf an effect would place one or more counters on a permanent, it places twice that many of those counters on that permanent instead. +Text:If an effect would put one or more tokens onto the battlefield, it puts twice that many of those tokens onto the battlefield instead. +R:Event$ AddCounter | ActiveZones$ Command | ValidCard$ Permanent | EffectOnly$ True | ReplaceWith$ AddDoubleCounters | Description$ If an effect would place one or more counters on a permanent, it places twice that many of those counters on that permanent instead. +SVar:AddDoubleCounters:DB$ PutCounter | Defined$ ReplacedCard | CounterType$ ReplacedCounterType | CounterNum$ X | References$ X +SVar:X:ReplaceCount$CounterNum/Twice T:Mode$ PlanarDice | Result$ Chaos | TriggerZones$ Command | Execute$ RolledChaos | TriggerDescription$ Whenever you roll {C}, until end of turn, whenever you tap a land for mana, add one mana to your mana pool of any type that land produced. SVar:RolledChaos:AB$ Effect | Cost$ 0 | AILogic$ Always | Triggers$ TrigTapForMana | SVars$ TrigMana SVar:TrigTapForMana:Mode$ TapsForMana | TriggerZones$ Command | ValidCard$ Land.YouCtrl | Execute$ TrigMana | Static$ True | TriggerDescription$ Whenever you tap a land for mana, add one mana to your mana pool of any type that land produced. diff --git a/forge-gui/src/main/java/forge/game/ability/AbilityUtils.java b/forge-gui/src/main/java/forge/game/ability/AbilityUtils.java index 9a36cb0a482..09d67bfaecc 100644 --- a/forge-gui/src/main/java/forge/game/ability/AbilityUtils.java +++ b/forge-gui/src/main/java/forge/game/ability/AbilityUtils.java @@ -39,7 +39,9 @@ public class AbilityUtils { public static CounterType getCounterType(String name, SpellAbility sa) throws Exception { CounterType counterType; - + if ("ReplacedCounterType".equals(name)) { + name = (String) sa.getReplacingObject("CounterType"); + } try { counterType = CounterType.getType(name); } catch (Exception e) { diff --git a/forge-gui/src/main/java/forge/game/ability/effects/CountersPutEffect.java b/forge-gui/src/main/java/forge/game/ability/effects/CountersPutEffect.java index b6faa98f26f..5f8c87c068c 100644 --- a/forge-gui/src/main/java/forge/game/ability/effects/CountersPutEffect.java +++ b/forge-gui/src/main/java/forge/game/ability/effects/CountersPutEffect.java @@ -91,7 +91,7 @@ public class CountersPutEffect extends SpellAbilityEffect { final Zone zone = tgtCard.getGame().getZoneOf(tgtCard); if (zone == null || zone.is(ZoneType.Battlefield) || zone.is(ZoneType.Stack)) { if (remember) { - final int value = tgtCard.getTotalCountersToAdd(counterType, counterAmount, true); + final int value = tgtCard.getTotalCountersToAdd(); tgtCard.addCountersAddedBy(card, counterType, value); } tgtCard.addCounter(counterType, counterAmount, true); diff --git a/forge-gui/src/main/java/forge/game/card/Card.java b/forge-gui/src/main/java/forge/game/card/Card.java index ea06344deb8..12ffd541fc0 100644 --- a/forge-gui/src/main/java/forge/game/card/Card.java +++ b/forge-gui/src/main/java/forge/game/card/Card.java @@ -250,6 +250,8 @@ public class Card extends GameEntity implements Comparable { // Zone-changing spells should store card's zone here private Zone currentZone = null; + private int countersAdded = 0; + // Enumeration for CMC request types public enum SplitCMCMode { CurrentSideCMC, @@ -1128,22 +1130,37 @@ public class Card extends GameEntity implements Comparable { return true; } - public final int getTotalCountersToAdd(final CounterType counterType, final int baseAmount, final boolean applyMultiplier) { - if (this.canReceiveCounters(counterType)) { - final int multiplier = applyMultiplier ? this.getController().getCounterDoublersMagnitude(counterType) : 1; - int result = multiplier * baseAmount; - if (counterType == CounterType.DREAM && this.hasKeyword("CARDNAME can't have more than seven dream counters on it.")) { - result = Math.min(7 - this.getCounters(CounterType.DREAM), result); - } - return result; - } - return 0; + public final int getTotalCountersToAdd() { + return countersAdded; + } + + public final void setTotalCountersToAdd(int value) { + countersAdded = value; } public final void addCounter(final CounterType counterType, final int n, final boolean applyMultiplier) { - final int addAmount = getTotalCountersToAdd(counterType, n, applyMultiplier); - if (addAmount == 0) + int addAmount = n; + final HashMap repParams = new HashMap(); + repParams.put("Event", "AddCounter"); + repParams.put("Affected", this); + repParams.put("CounterType", counterType); + repParams.put("CounterNum", addAmount); + repParams.put("EffectOnly", applyMultiplier); + if (this.getGame().getReplacementHandler().run(repParams) != ReplacementResult.NotReplaced) { return; + } + if (this.canReceiveCounters(counterType)) { + if (counterType == CounterType.DREAM && this.hasKeyword("CARDNAME can't have more than seven dream counters on it.")) { + addAmount = Math.min(7 - this.getCounters(CounterType.DREAM), addAmount); + } + } else { + addAmount = 0; + } + + if (addAmount == 0) { + return; + } + this.setTotalCountersToAdd(addAmount); Integer oldValue = this.counters.get(counterType); int newValue = addAmount + (oldValue == null ? 0 : oldValue.intValue()); diff --git a/forge-gui/src/main/java/forge/game/player/Player.java b/forge-gui/src/main/java/forge/game/player/Player.java index e87657d8a88..1a70d770244 100644 --- a/forge-gui/src/main/java/forge/game/player/Player.java +++ b/forge-gui/src/main/java/forge/game/player/Player.java @@ -2857,19 +2857,11 @@ public class Player extends GameEntity implements Comparable { return CardLists.filter(getCardsIn(ZoneType.Battlefield), CardPredicates.isColor(MagicColor.fromName(color))); } - public int getCounterDoublersMagnitude(final CounterType type) { - int counterDoublers = getCardsIn(ZoneType.Battlefield, "Doubling Season").size() - + CardLists.filter(getGame().getCardsIn(ZoneType.Command), - CardPredicates.nameEquals("Selesnya Loft Gardens")).size(); - if (type == CounterType.P1P1) { - counterDoublers += getCardsIn(ZoneType.Battlefield, "Corpsejack Menace").size(); - } - return 1 << counterDoublers; - } - public int getTokenDoublersMagnitude() { final int tokenDoublers = getCardsIn(ZoneType.Battlefield, "Parallel Lives").size() + getCardsIn(ZoneType.Battlefield, "Doubling Season").size() + + CardLists.filter(getGame().getCardsIn(ZoneType.Battlefield), + CardPredicates.nameEquals("Primal Vigor")).size() + CardLists.filter(getGame().getCardsIn(ZoneType.Command), CardPredicates.nameEquals("Selesnya Loft Gardens")).size();; return 1 << tokenDoublers; // pow(a,0) = 1; pow(a,1) = a diff --git a/forge-gui/src/main/java/forge/game/replacement/ReplaceAddCounter.java b/forge-gui/src/main/java/forge/game/replacement/ReplaceAddCounter.java new file mode 100644 index 00000000000..0e7e4cbf9f6 --- /dev/null +++ b/forge-gui/src/main/java/forge/game/replacement/ReplaceAddCounter.java @@ -0,0 +1,67 @@ +package forge.game.replacement; + +import java.util.Map; + +import forge.game.card.Card; +import forge.game.card.CounterType; +import forge.game.spellability.SpellAbility; + +/** + * TODO: Write javadoc for this type. + * + */ +public class ReplaceAddCounter extends ReplacementEffect { + + /** + * + * ReplaceProduceMana. + * @param mapParams   HashMap + * @param host   Card + */ + public ReplaceAddCounter(final Map mapParams, final Card host, final boolean intrinsic) { + super(mapParams, host, intrinsic); + } + + /* (non-Javadoc) + * @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap) + */ + @Override + public boolean canReplace(Map runParams) { + if (!runParams.get("Event").equals("AddCounter")) { + return false; + } + + if (mapParams.containsKey("EffectOnly")) { + final Boolean effectOnly = (Boolean) runParams.get("EffectOnly"); + if (!effectOnly) { + return false; + } + } + + if (mapParams.containsKey("ValidCard")) { + if (!matchesValid(runParams.get("Affected"), this.getMapParams().get("ValidCard").split(","), this.getHostCard())) { + return false; + } + } + + if (mapParams.containsKey("ValidCounterType")) { + String type = this.getMapParams().get("ValidCounterType"); + if (CounterType.getType(type) != runParams.get("CounterType")) { + return false; + } + } + + return true; + } + + /* (non-Javadoc) + * @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.HashMap, forge.card.spellability.SpellAbility) + */ + @Override + public void setReplacingObjects(Map runParams, SpellAbility sa) { + sa.setReplacingObject("CounterNum", runParams.get("CounterNum")); + sa.setReplacingObject("CounterType", ((CounterType) runParams.get("CounterType")).getName()); + sa.setReplacingObject("Card", runParams.get("Affected")); + } + +} diff --git a/forge-gui/src/main/java/forge/game/replacement/ReplacementType.java b/forge-gui/src/main/java/forge/game/replacement/ReplacementType.java index 8984eabe954..7bb7a79de3e 100644 --- a/forge-gui/src/main/java/forge/game/replacement/ReplacementType.java +++ b/forge-gui/src/main/java/forge/game/replacement/ReplacementType.java @@ -11,6 +11,7 @@ import forge.game.card.Card; * */ public enum ReplacementType { + AddCounter(ReplaceAddCounter.class), Counter(ReplaceCounter.class), DamageDone(ReplaceDamage.class), Destroy(ReplaceDestroy.class),