diff --git a/forge-game/src/main/java/forge/game/ability/effects/SacrificeEffect.java b/forge-game/src/main/java/forge/game/ability/effects/SacrificeEffect.java index 0aff84600ee..d900672458e 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/SacrificeEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/SacrificeEffect.java @@ -68,7 +68,7 @@ public class SacrificeEffect extends SpellAbilityEffect { int n = card.getCounters(CounterEnumType.AGE); if (n > 0) { Cost cumCost = new Cost(sa.getParam("CumulativeUpkeep"), true); - payCost.mergeTo(cumCost, n); + payCost.mergeTo(cumCost, n, sa); } game.updateLastStateForCard(card); diff --git a/forge-game/src/main/java/forge/game/cost/Cost.java b/forge-game/src/main/java/forge/game/cost/Cost.java index 9d5fc7839f2..e44ead8ae27 100644 --- a/forge-game/src/main/java/forge/game/cost/Cost.java +++ b/forge-game/src/main/java/forge/game/cost/Cost.java @@ -907,7 +907,7 @@ public class Cost implements Serializable { return sb.toString(); } - public void mergeTo(Cost source, int amt) { + public void mergeTo(Cost source, int amt, final SpellAbility sa) { // multiply to create the full cost if (amt > 1) { // to double itself we need to work on a copy @@ -918,13 +918,16 @@ public class Cost implements Serializable { } } // combine costs (these shouldn't mix together) - this.add(source, false); + this.add(source, false, sa); } public Cost add(Cost cost1) { return add(cost1, true); } public Cost add(Cost cost1, boolean mergeAdditional) { + return add(cost1, mergeAdditional, null); + } + public Cost add(Cost cost1, boolean mergeAdditional, final SpellAbility sa) { CostPartMana costPart2 = this.getCostMana(); List toRemove = Lists.newArrayList(); for (final CostPart part : cost1.getCostParts()) { @@ -954,17 +957,21 @@ public class Cost implements Serializable { part instanceof CostExile))) { boolean alreadyAdded = false; for (final CostPart other : costParts) { + Integer otherAmount = other.convertAmount(); + // support X loyalty + if (otherAmount == null && sa != null && sa.isPwAbility()) { + otherAmount = other.getAbilityAmount(sa); + } if ((other.getClass().equals(part.getClass()) || (part instanceof CostPutCounter && ((CostPutCounter)part).getCounter().is(CounterEnumType.LOYALTY))) && part.getType().equals(other.getType()) && StringUtils.isNumeric(part.getAmount()) && - StringUtils.isNumeric(other.getAmount())) { - String amount = String.valueOf(part.convertAmount() + other.convertAmount()); + otherAmount != null) { + String amount = String.valueOf(part.convertAmount() + otherAmount); if (part instanceof CostPutCounter) { // CR 606.5 path for Carth - // TODO support X if (other instanceof CostPutCounter && ((CostPutCounter)other).getCounter().equals(((CostPutCounter) part).getCounter())) { costParts.add(new CostPutCounter(amount, ((CostPutCounter) part).getCounter(), part.getType(), part.getTypeDescription())); } else if (other instanceof CostRemoveCounter && ((CostRemoveCounter)other).counter.is(CounterEnumType.LOYALTY)) { - Integer counters = other.convertAmount() - part.convertAmount(); + Integer counters = otherAmount - part.convertAmount(); // the cost can turn positive if multiple Carth raise it if (counters < 0) { costParts.add(new CostPutCounter(String.valueOf(counters *-1), CounterType.get(CounterEnumType.LOYALTY), part.getType(), part.getTypeDescription())); diff --git a/forge-game/src/main/java/forge/game/cost/CostAdjustment.java b/forge-game/src/main/java/forge/game/cost/CostAdjustment.java index 6f755aa7e53..998ea46b7f4 100644 --- a/forge-game/src/main/java/forge/game/cost/CostAdjustment.java +++ b/forge-game/src/main/java/forge/game/cost/CostAdjustment.java @@ -162,7 +162,7 @@ public class CostAdjustment { } if (count > 0) { Cost part = new Cost(scost, sa.isAbility(), sa.getHostCard().equals(hostCard)); - cost.mergeTo(part, count); + cost.mergeTo(part, count, sa); } } diff --git a/forge-gui/res/cardsfolder/k/knight_rampager.txt b/forge-gui/res/cardsfolder/k/knight_rampager.txt index 362cf06052e..9b1a5b26ab6 100644 --- a/forge-gui/res/cardsfolder/k/knight_rampager.txt +++ b/forge-gui/res/cardsfolder/k/knight_rampager.txt @@ -5,7 +5,8 @@ PT:6/5 K:Trample T:Mode$ Phase | Phase$ BeginCombat | ValidPlayer$ You | Execute$ TrigChoose | TriggerZones$ Battlefield | TriggerDescription$ Frenzied Rampage — At the beginning of combat on your turn, choose an opponent at random. CARDNAME attacks that player this combat if able. SVar:TrigChoose:DB$ ChoosePlayer | Defined$ You | Choices$ Opponent | Random$ True | SubAbility$ DBPump -SVar:DBPump:DB$ Pump | Defined$ Self | KW$ HIDDEN CARDNAME attacks specific player each combat if able:ChosenPlayer | Duration$ UntilEndOfCombat +SVar:DBPump:DB$ Animate | Defined$ Self | staticAbilities$ AttackChosen | Duration$ UntilEndOfCombat +SVar:AttackChosen:Mode$ MustAttack | ValidCreature$ Card.Self | MustAttack$ ChosenPlayer T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigChooseBis | TriggerDescription$ When CARDNAME dies, it deals 4 damage to target opponent chosen at random. SVar:TrigChooseBis:DB$ ChoosePlayer | Defined$ You | Choices$ Opponent | Random$ True | SubAbility$ DBDealDamage SVar:DBDealDamage:DB$ DealDamage | Defined$ ChosenPlayer | NumDmg$ 4 | SubAbility$ DBCleanup