From ebce943f38b7fa867b61953955c88e0fe1c6ac9b Mon Sep 17 00:00:00 2001 From: moomarc Date: Fri, 31 May 2013 17:20:41 +0000 Subject: [PATCH] - Implemented Offering ability from BOK. - Added Patron of the Akki, Patron of the Kitsune, Patron of the Moon and Patron of the Orochi --- .gitattributes | 4 ++ res/cardsfolder/p/patron_of_the_akki.txt | 11 +++++ res/cardsfolder/p/patron_of_the_kitsune.txt | 11 +++++ res/cardsfolder/p/patron_of_the_moon.txt | 11 +++++ res/cardsfolder/p/patron_of_the_orochi.txt | 10 +++++ src/main/java/forge/Card.java | 22 +++++++++ .../card/ability/effects/SacrificeEffect.java | 2 +- .../java/forge/card/cost/CostPartMana.java | 27 +++++++++-- .../forge/card/mana/ManaCostBeingPaid.java | 45 ++++++++++++++++++- .../forge/card/spellability/SpellAbility.java | 43 ++++++++++++++++++ .../spellability/SpellAbilityRestriction.java | 2 +- src/main/java/forge/game/GameActionUtil.java | 20 +++++++++ .../java/forge/game/ai/ComputerUtilMana.java | 10 +++++ .../java/forge/game/phase/CombatUtil.java | 2 +- src/main/java/forge/game/phase/Upkeep.java | 2 +- .../forge/game/player/PlayerController.java | 2 +- .../forge/game/player/PlayerControllerAi.java | 2 +- .../game/player/PlayerControllerHuman.java | 6 ++- .../java/forge/gui/input/InputPayMana.java | 17 +++++-- .../gui/input/InputPayManaOfCostPayment.java | 10 ++++- .../forge/gui/input/InputPayManaSimple.java | 6 +++ 21 files changed, 249 insertions(+), 16 deletions(-) create mode 100644 res/cardsfolder/p/patron_of_the_akki.txt create mode 100644 res/cardsfolder/p/patron_of_the_kitsune.txt create mode 100644 res/cardsfolder/p/patron_of_the_moon.txt create mode 100644 res/cardsfolder/p/patron_of_the_orochi.txt diff --git a/.gitattributes b/.gitattributes index c6fe2781f8f..b85159b0edb 100644 --- a/.gitattributes +++ b/.gitattributes @@ -7827,6 +7827,10 @@ res/cardsfolder/p/patriarchs_desire.txt -text svneol=unset#text/plain res/cardsfolder/p/patricians_scorn.txt -text svneol=unset#text/plain res/cardsfolder/p/patrol_hound.txt -text res/cardsfolder/p/patrol_signaler.txt svneol=native#text/plain +res/cardsfolder/p/patron_of_the_akki.txt -text +res/cardsfolder/p/patron_of_the_kitsune.txt -text +res/cardsfolder/p/patron_of_the_moon.txt -text +res/cardsfolder/p/patron_of_the_orochi.txt -text res/cardsfolder/p/patron_of_the_wild.txt svneol=native#text/plain res/cardsfolder/p/patron_wizard.txt svneol=native#text/plain res/cardsfolder/p/pattern_of_rebirth.txt svneol=native#text/plain diff --git a/res/cardsfolder/p/patron_of_the_akki.txt b/res/cardsfolder/p/patron_of_the_akki.txt new file mode 100644 index 00000000000..a6752f7ab7f --- /dev/null +++ b/res/cardsfolder/p/patron_of_the_akki.txt @@ -0,0 +1,11 @@ +Name:Patron of the Akki +ManaCost:4 R R +Types:Legendary Creature Spirit +PT:5/5 +K:Goblin offering +T:Mode$ Attacks | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigPump | TriggerDescription$ Whenever CARDNAME attacks, creatures you control get +2/+0 until end of turn. +SVar:TrigPump:AB$ PumpAll | Cost$ 0 | ValidCards$ Creature.YouCtrl | NumAtt$ 2 +SVar:RemAIDeck:True +SVar:Picture:http://www.wizards.com/global/images/magic/general/patron_of_the_akki.jpg +Oracle:Goblin offering (You may cast this card any time you could cast an instant by sacrificing a Goblin and paying the difference in mana costs between this and the sacrificed Goblin. Mana cost includes color.)\nWhenever Patron of the Akki attacks, creatures you control get +2/+0 until end of turn. +SetInfo:BOK Rare \ No newline at end of file diff --git a/res/cardsfolder/p/patron_of_the_kitsune.txt b/res/cardsfolder/p/patron_of_the_kitsune.txt new file mode 100644 index 00000000000..b5a41ed61ed --- /dev/null +++ b/res/cardsfolder/p/patron_of_the_kitsune.txt @@ -0,0 +1,11 @@ +Name:Patron of the Kitsune +ManaCost:4 W W +Types:Legendary Creature Spirit +PT:5/6 +K:Fox offering +T:Mode$ Attacks | ValidCard$ Creature | TriggerZones$ Battlefield | Execute$ PatronLife | OptionalDecider$ You | TriggerDescription$ Whenever a creature attacks, you gain 1 life. +SVar:PatronLife:AB$ GainLife | Cost$ 0 | LifeAmount$ 1 +SVar:RemAIDeck:True +SVar:Picture:http://www.wizards.com/global/images/magic/general/patron_of_the_kitsune.jpg +Oracle:Fox offering (You may cast this card any time you could cast an instant by sacrificing a Fox and paying the difference in mana costs between this and the sacrificed Fox. Mana cost includes color.)\nWhenever a creature attacks, you may gain 1 life. +SetInfo:BOK Rare \ No newline at end of file diff --git a/res/cardsfolder/p/patron_of_the_moon.txt b/res/cardsfolder/p/patron_of_the_moon.txt new file mode 100644 index 00000000000..d5a123cf275 --- /dev/null +++ b/res/cardsfolder/p/patron_of_the_moon.txt @@ -0,0 +1,11 @@ +Name:Patron of the Moon +ManaCost:5 U U +Types:Legendary Creature Spirit +PT:5/4 +K:Moonfolk offering +K:Flying +A:AB$ ChangeZone | Cost$ 1 | ChangeNum$ 2 | Origin$ Hand | Destination$ Battlefield | Tapped$ True | ChangeType$ Land.YouCtrl | SpellDescription$ Put up to two land cards from your hand onto the battlefield tapped. +SVar:RemAIDeck:True +SVar:Picture:http://www.wizards.com/global/images/magic/general/patron_of_the_moon.jpg +Oracle:Moonfolk offering (You may cast this card any time you could cast an instant by sacrificing a Moonfolk and paying the difference in mana costs between this and the sacrificed Moonfolk. Mana cost includes color.)\nFlying\n{1}: Put up to two land cards from your hand onto the battlefield tapped. +SetInfo:BOK Rare \ No newline at end of file diff --git a/res/cardsfolder/p/patron_of_the_orochi.txt b/res/cardsfolder/p/patron_of_the_orochi.txt new file mode 100644 index 00000000000..4f8a741cdc7 --- /dev/null +++ b/res/cardsfolder/p/patron_of_the_orochi.txt @@ -0,0 +1,10 @@ +Name:Patron of the Orochi +ManaCost:6 G G +Types:Legendary Creature Spirit +PT:7/7 +K:Snake offering +A:AB$ UntapAll | Cost$ T | ValidCards$ Forest,Creature.Green | ActivationLimit$ 1 | SpellDescription$ Untap all Forests and all green creatures. Activate this ability only once each turn. +SVar:RemAIDeck:True +SVar:Picture:http://www.wizards.com/global/images/magic/general/patron_of_the_orochi.jpg +Oracle:Snake offering (You may cast this card any time you could cast an instant by sacrificing a Snake and paying the difference in mana costs between this and the sacrificed Snake. Mana cost includes color.)\n{T}: Untap all Forests and all green creatures. Activate this ability only once each turn. +SetInfo:BOK Rare \ No newline at end of file diff --git a/src/main/java/forge/Card.java b/src/main/java/forge/Card.java index 0cd29d4832d..71f68339aa3 100644 --- a/src/main/java/forge/Card.java +++ b/src/main/java/forge/Card.java @@ -2149,6 +2149,17 @@ public class Card extends GameEntity implements Comparable { 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.endsWith(" offering")) { + String offeringType = keyword.split(" ")[0]; + if (sb.length() != 0) { + sb.append("\r\n"); + } + sbLong.append(keywords.get(i)); + sbLong.append(" (You may cast this card any time you could cast an instant by sacrificing a "); + sbLong.append(offeringType); + sbLong.append("and paying the difference in mana costs between this and the sacrificed "); + sbLong.append(offeringType); + sbLong.append(". Mana cost includes color.)"); } else if (keyword.startsWith("Soulbond")) { sbLong.append(keywords.get(i)); sbLong.append(" (You may pair this creature "); @@ -2429,6 +2440,17 @@ public class Card extends GameEntity implements Comparable { sb.delete(sb.lastIndexOf("\r\n"), sb.lastIndexOf("\r\n") + 3); } 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.)\r\n"); + } else if (keyword.endsWith(" offering")) { + if (sb.toString().endsWith("\r\n\r\n")) { + sb.delete(sb.lastIndexOf("\r\n"), sb.lastIndexOf("\r\n") + 3); + } + String offeringType = keyword.split(" ")[0]; + sb.append(keyword); + sb.append(" (You may cast this card any time you could cast an instant by sacrificing a "); + sb.append(offeringType); + sb.append("and paying the difference in mana costs between this and the sacrificed "); + sb.append(offeringType); + sb.append(". Mana cost includes color.)"); } else if (keyword.equals("Remove CARDNAME from your deck before playing if you're not playing for ante.")) { if (sb.toString().endsWith("\r\n\r\n")) { sb.delete(sb.lastIndexOf("\r\n"), sb.lastIndexOf("\r\n") + 3); diff --git a/src/main/java/forge/card/ability/effects/SacrificeEffect.java b/src/main/java/forge/card/ability/effects/SacrificeEffect.java index 9f4e6c8c5ec..d53745f49a8 100644 --- a/src/main/java/forge/card/ability/effects/SacrificeEffect.java +++ b/src/main/java/forge/card/ability/effects/SacrificeEffect.java @@ -61,7 +61,7 @@ public class SacrificeEffect extends SpellAbilityEffect { choosenToSacrifice = Aggregates.random(validTargets, Math.min(amount, validTargets.size())); } else { boolean isOptional = sa.hasParam("Optional"); - choosenToSacrifice = p.getController().choosePermanentsToSacrifice(validTargets, valid, amount, sa, destroy, isOptional); + choosenToSacrifice = p.getController().choosePermanentsToSacrifice(validTargets, valid, amount, sa, destroy, isOptional, false); } for(Card sac : choosenToSacrifice) { diff --git a/src/main/java/forge/card/cost/CostPartMana.java b/src/main/java/forge/card/cost/CostPartMana.java index 3ecf7d7ffa7..fac1b8fb8cb 100644 --- a/src/main/java/forge/card/cost/CostPartMana.java +++ b/src/main/java/forge/card/cost/CostPartMana.java @@ -129,6 +129,10 @@ public class CostPartMana extends CostPart { InputPayMana inpPayment; toPay.applySpellCostChange(ability); + if (ability.isOffering() && ability.getSacrificedAsOffering() == null) { + System.out.println("Sacrifice input for Offering cancelled"); + return false; + } if (!toPay.isPaid()) { inpPayment = new InputPayManaOfCostPayment(toPay, ability); Singletons.getControl().getInputQueue().setInputAndWait(inpPayment); @@ -139,19 +143,36 @@ public class CostPartMana extends CostPart { source.setSunburstValue(toPay.getSunburst()); } if (this.getAmountOfX() > 0) { - if( !ability.isAnnouncing("X") && !xWasBilled) { + if (!ability.isAnnouncing("X") && !xWasBilled) { source.setXManaCostPaid(0); inpPayment = new InputPayManaX(ability, this.getAmountOfX(), this.canXbe0()); Singletons.getControl().getInputQueue().setInputAndWait(inpPayment); - if(!inpPayment.isPaid()) + if (!inpPayment.isPaid()) { return false; + } } else { int x = AbilityUtils.calculateAmount(source, "X", ability); source.setXManaCostPaid(x); } } + + // Handle convoke and offerings if InputPayManaOfCostPayment was skipped because cost was reduced to 0 + if (ability.isOffering() && ability.getSacrificedAsOffering() != null) { + System.out.println("Finishing up Offering"); + final Card offering = ability.getSacrificedAsOffering(); + offering.setUsedToPay(false); + game.getAction().sacrifice(offering, ability); + ability.resetSacrificedAsOffering(); + } + if (ability.getTappedForConvoke() != null) { + for (final Card c : ability.getTappedForConvoke()) { + c.setTapped(false); + c.tap(); + } + ability.clearTappedForConvoke(); + } return true; - + } /* (non-Javadoc) diff --git a/src/main/java/forge/card/mana/ManaCostBeingPaid.java b/src/main/java/forge/card/mana/ManaCostBeingPaid.java index 300652be02a..4d90a2fbd7a 100644 --- a/src/main/java/forge/card/mana/ManaCostBeingPaid.java +++ b/src/main/java/forge/card/mana/ManaCostBeingPaid.java @@ -398,6 +398,19 @@ public class ManaCostBeingPaid { increaseColorlessMana(extra.getGenericCost()); } + public final void determineManaCostDifference(final ManaCost subThisManaCost) { + for (ManaCostShard shard : subThisManaCost.getShards()) { + if (shard == ManaCostShard.X) { + cntX--; + } else if (unpaidShards.containsKey(shard)) { + decreaseShard(shard, 1); + } else { + decreaseColorlessMana(1); + } + } + decreaseColorlessMana(subThisManaCost.getGenericCost()); + } + /** * To string. * @@ -554,6 +567,9 @@ public class ManaCostBeingPaid { for (final StaticAbility stAb : reduceAbilities) { stAb.applyAbility("ReduceCost", spell, this); } + if (spell.isSpell() && spell.isOffering()) { // cost reduction from offerings + adjustCostByOffering(sa, spell); + } // Set cost (only used by Trinisphere) is applied last for (final StaticAbility stAb : setAbilities) { @@ -562,7 +578,7 @@ public class ManaCostBeingPaid { } // GetSpellCostChange private void adjustCostByConvoke(final SpellAbility sa, final SpellAbility spell) { - + List untappedCreats = CardLists.filter(spell.getActivatingPlayer().getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.CREATURES); untappedCreats = CardLists.filter(untappedCreats, CardPredicates.Presets.UNTAPPED); @@ -636,6 +652,33 @@ public class ManaCostBeingPaid { return usableColors; } + private void adjustCostByOffering(final SpellAbility sa, final SpellAbility spell) { + String offeringType = ""; + for (String kw : sa.getSourceCard().getKeyword()) { + if (kw.endsWith(" offering")) { + offeringType = kw.split(" ")[0]; + break; + } + } + + Card toSac = null; + List canOffer = CardLists.filter(spell.getActivatingPlayer().getCardsIn(ZoneType.Battlefield), + CardPredicates.isType(offeringType)); + + final List toSacList = sa.getSourceCard().getController().getController().choosePermanentsToSacrifice(canOffer, + offeringType, 1, spell, false, false, true); + if (!toSacList.isEmpty()) { + toSac = toSacList.get(0); + } else { + return; + } + + determineManaCostDifference(toSac.getManaCost()); + + sa.setSacrificedAsOffering(toSac); + toSac.setUsedToPay(true); //stop it from interfering with mana input + } + public String getSourceRestriction() { return sourceRestriction; } diff --git a/src/main/java/forge/card/spellability/SpellAbility.java b/src/main/java/forge/card/spellability/SpellAbility.java index 567e0d474df..096642465b6 100644 --- a/src/main/java/forge/card/spellability/SpellAbility.java +++ b/src/main/java/forge/card/spellability/SpellAbility.java @@ -76,6 +76,7 @@ public abstract class SpellAbility implements ISpellAbility { private boolean replicate = false; private boolean cycling = false; private boolean delve = false; + private boolean offering = false; private Card targetCard; /** The chosen target. */ @@ -100,6 +101,7 @@ public abstract class SpellAbility implements ISpellAbility { private HashMap replacingObjects = new HashMap(); private List tappedForConvoke = new ArrayList(); + private Card sacrificedAsOffering = null; private HashMap sVars = new HashMap(); @@ -1309,6 +1311,47 @@ public abstract class SpellAbility implements ISpellAbility { } } + /** + * Returns whether the SA is a patron offering. + */ + public boolean isOffering() { + return this.offering; + } + + /** + * Sets the SA as a patron offering. + * + * @param c card sacrificed for a patron offering + */ + public void setIsOffering(final boolean bOffering) { + this.offering = bOffering; + } + + /** + * Sets the card sacrificed for a patron offering. + * + * @param c card sacrificed for a patron offering + */ + public void setSacrificedAsOffering(final Card c) { + this.sacrificedAsOffering = c; + } + + /** + * Gets the card sacrificed for a patron offering. + * + * @return the card sacrificed for a patron offering + */ + public Card getSacrificedAsOffering() { + return this.sacrificedAsOffering; + } + + /** + * Clear the card sacrificed for a patron offering. + */ + public void resetSacrificedAsOffering() { + this.sacrificedAsOffering = null; + } + /** * @return the splicedCards */ diff --git a/src/main/java/forge/card/spellability/SpellAbilityRestriction.java b/src/main/java/forge/card/spellability/SpellAbilityRestriction.java index 4cd57a245a8..af618c3f0a4 100644 --- a/src/main/java/forge/card/spellability/SpellAbilityRestriction.java +++ b/src/main/java/forge/card/spellability/SpellAbilityRestriction.java @@ -292,7 +292,7 @@ public class SpellAbilityRestriction extends SpellAbilityVariables { * @return a boolean. */ public final boolean canPlay(final Card c, final SpellAbility sa) { - if (c.isPhasedOut()) { + if (c.isPhasedOut() || c.isUsedToPay()) { return false; } diff --git a/src/main/java/forge/game/GameActionUtil.java b/src/main/java/forge/game/GameActionUtil.java index 1ae33c77f90..500a3bf0be5 100644 --- a/src/main/java/forge/game/GameActionUtil.java +++ b/src/main/java/forge/game/GameActionUtil.java @@ -792,6 +792,26 @@ public final class GameActionUtil { newSA.setDescription(sa.getDescription() + " (by paying " + actualcost.toSimpleString() + " instead of its mana cost)"); alternatives.add(newSA); } + if (sa.isSpell() && keyword.endsWith(" offering")) { + final String offeringType = keyword.split(" ")[0]; + List canOffer = CardLists.filter(sa.getSourceCard().getController().getCardsIn(ZoneType.Battlefield), + CardPredicates.isType(offeringType)); + if (source.getController().hasKeyword("You can't sacrifice creatures to cast spells or activate abilities.")) { + canOffer = CardLists.getNotType(canOffer, "Creature"); + } + if (!canOffer.isEmpty()) { + final SpellAbility newSA = sa.copy(); + SpellAbilityRestriction sar = new SpellAbilityRestriction(); + sar.setVariables(sa.getRestrictions()); + sar.setInstantSpeed(true); + newSA.setRestrictions(sar); + newSA.setBasicSpell(false); + newSA.setIsOffering(true); + newSA.setPayCosts(sa.getPayCosts()); + newSA.setDescription(sa.getDescription() + " (" + offeringType + " offering)"); + alternatives.add(newSA); + } + } if (sa.hasParam("Equip") && sa instanceof AbilityActivated && keyword.equals("EquipInstantSpeed")) { final SpellAbility newSA = ((AbilityActivated) sa).getCopy(); SpellAbilityRestriction sar = new SpellAbilityRestriction(); diff --git a/src/main/java/forge/game/ai/ComputerUtilMana.java b/src/main/java/forge/game/ai/ComputerUtilMana.java index 1d6c4cc550f..4ab5925befc 100644 --- a/src/main/java/forge/game/ai/ComputerUtilMana.java +++ b/src/main/java/forge/game/ai/ComputerUtilMana.java @@ -194,6 +194,16 @@ public class ComputerUtilMana { manapool.clearManaPaid(sa, test); + // handle Offerings for AI + if (sa.isOffering() && sa.getSacrificedAsOffering() != null) { + final Card offering = sa.getSacrificedAsOffering(); + offering.setUsedToPay(false); + if (cost.isPaid() && !test) { + sa.getSourceCard().getController().getGame().getAction().sacrifice(offering, sa); + } + sa.resetSacrificedAsOffering(); + } + if( DEBUG_MANA_PAYMENT ) System.err.printf("%s > [%s] payment has %s (%s +%d) for (%s) %s:%n\t%s%n%n", FThreads.debugGetCurrThreadId(), test ? "test" : "PROD", cost.isPaid() ? "*PAID*" : "failed", originalCost, extraMana, sa.getSourceCard(), sa.toUnsuppressedString(), StringUtils.join(paymentPlan, "\n\t") ); diff --git a/src/main/java/forge/game/phase/CombatUtil.java b/src/main/java/forge/game/phase/CombatUtil.java index 3efad5c9ea4..a9196619129 100644 --- a/src/main/java/forge/game/phase/CombatUtil.java +++ b/src/main/java/forge/game/phase/CombatUtil.java @@ -1048,7 +1048,7 @@ public class CombatUtil { final Player opponent = game.getCombat().getDefendingPlayerRelatedTo(c).get(0); //List list = AbilityUtils.filterListByType(opponent.getCardsIn(ZoneType.Battlefield), "Permanent", this); final List list = opponent.getCardsIn(ZoneType.Battlefield); - List toSac = opponent.getController().choosePermanentsToSacrifice(list, "Card", a, this, false, false); + List toSac = opponent.getController().choosePermanentsToSacrifice(list, "Card", a, this, false, false, false); for(Card sacd : toSac) { game.getAction().sacrifice(sacd, this); diff --git a/src/main/java/forge/game/phase/Upkeep.java b/src/main/java/forge/game/phase/Upkeep.java index 731cae4078e..80f4c12c43e 100644 --- a/src/main/java/forge/game/phase/Upkeep.java +++ b/src/main/java/forge/game/phase/Upkeep.java @@ -455,7 +455,7 @@ public class Upkeep extends Phase { lowest.add(c); } - List toSac = player.getController().choosePermanentsToSacrifice(lowest, "Select creature with power: " + power + " to destroy.", 1, this, true, false); + List toSac = player.getController().choosePermanentsToSacrifice(lowest, "Select creature with power: " + power + " to destroy.", 1, this, true, false, false); game.getAction().destroyNoRegeneration(toSac.get(0), this); } } // resolve diff --git a/src/main/java/forge/game/player/PlayerController.java b/src/main/java/forge/game/player/PlayerController.java index 003053a9979..50de157d8ef 100644 --- a/src/main/java/forge/game/player/PlayerController.java +++ b/src/main/java/forge/game/player/PlayerController.java @@ -90,7 +90,7 @@ public abstract class PlayerController { public abstract Map assignCombatDamage(Card attacker, List blockers, int damageDealt, GameEntity defender); public abstract Integer announceRequirements(SpellAbility ability, String announce, boolean allowZero); - public abstract List choosePermanentsToSacrifice(List validTargets, String validMessage, int amount, SpellAbility sa, boolean destroy, boolean isOptional); + public abstract List choosePermanentsToSacrifice(List validTargets, String validMessage, int amount, SpellAbility sa, boolean destroy, boolean isOptional, boolean canCancel); public abstract Target chooseTargets(SpellAbility ability); public Card chooseSingleCardForEffect(List sourceList, SpellAbility sa, String title) { return chooseSingleCardForEffect(sourceList, sa, title, false); } diff --git a/src/main/java/forge/game/player/PlayerControllerAi.java b/src/main/java/forge/game/player/PlayerControllerAi.java index b426599b2bc..66fcb6da1c1 100644 --- a/src/main/java/forge/game/player/PlayerControllerAi.java +++ b/src/main/java/forge/game/player/PlayerControllerAi.java @@ -118,7 +118,7 @@ public class PlayerControllerAi extends PlayerController { } @Override - public List choosePermanentsToSacrifice(List validTargets, String validMessage, int amount, SpellAbility sa, boolean destroy, boolean isOptional) { + public List choosePermanentsToSacrifice(List validTargets, String validMessage, int amount, SpellAbility sa, boolean destroy, boolean isOptional, boolean canCancel) { return ComputerUtil.choosePermanentsToSacrifice(player, validTargets, amount, sa, destroy, isOptional); } diff --git a/src/main/java/forge/game/player/PlayerControllerHuman.java b/src/main/java/forge/game/player/PlayerControllerHuman.java index 698ae0dedc4..1cbf18b4c98 100644 --- a/src/main/java/forge/game/player/PlayerControllerHuman.java +++ b/src/main/java/forge/game/player/PlayerControllerHuman.java @@ -210,7 +210,7 @@ public class PlayerControllerHuman extends PlayerController { * @see forge.game.player.PlayerController#choosePermanentsToSacrifice(java.util.List, int, forge.card.spellability.SpellAbility, boolean, boolean) */ @Override - public List choosePermanentsToSacrifice(List validTargets, String validMessage, int amount, SpellAbility sa, boolean destroy, boolean isOptional) { + public List choosePermanentsToSacrifice(List validTargets, String validMessage, int amount, SpellAbility sa, boolean destroy, boolean isOptional, boolean canCancel) { int max = Math.min(amount, validTargets.size()); if (max <= 0) return new ArrayList(); @@ -223,10 +223,12 @@ public class PlayerControllerHuman extends PlayerController { InputSelectCards inp = new InputSelectCardsFromList(min, max, validTargets); // TODO: Either compose a message here, or pass it as parameter from caller. inp.setMessage("Select %d " + validMessage + "(s) to sacrifice"); + inp.setCancelAllowed(canCancel); Singletons.getControl().getInputQueue().setInputAndWait(inp); - if( inp.hasCancelled() ) + if (inp.hasCancelled()) { return new ArrayList(); + } else return inp.getSelected(); } diff --git a/src/main/java/forge/gui/input/InputPayMana.java b/src/main/java/forge/gui/input/InputPayMana.java index 810ad5bd6de..73b33cde696 100644 --- a/src/main/java/forge/gui/input/InputPayMana.java +++ b/src/main/java/forge/gui/input/InputPayMana.java @@ -239,7 +239,7 @@ public abstract class InputPayMana extends InputSyncronizedBase { player.getZone(ZoneType.Battlefield).updateObservers(); } - protected boolean isAlredyPaid() { + protected boolean isAlreadyPaid() { if (manaCost.isPaid()) { bPaid = true; } @@ -256,7 +256,7 @@ public abstract class InputPayMana extends InputSyncronizedBase { } protected void onStateChanged() { - if( isAlredyPaid() ) { + if( isAlreadyPaid() ) { done(); stop(); } else @@ -282,6 +282,17 @@ public abstract class InputPayMana extends InputSyncronizedBase { saPaidFor.clearTappedForConvoke(); } } - + + protected void handleOfferings(boolean isCancelled) { + final Card offering = saPaidFor.getSacrificedAsOffering(); + if (offering != null) { + offering.setUsedToPay(false); + if (!isCancelled) { + game.getAction().sacrifice(offering, saPaidFor); + } + } + saPaidFor.resetSacrificedAsOffering(); + } + public boolean isPaid() { return bPaid; } } diff --git a/src/main/java/forge/gui/input/InputPayManaOfCostPayment.java b/src/main/java/forge/gui/input/InputPayManaOfCostPayment.java index d7ed00c74c7..4779bf185a0 100644 --- a/src/main/java/forge/gui/input/InputPayManaOfCostPayment.java +++ b/src/main/java/forge/gui/input/InputPayManaOfCostPayment.java @@ -39,11 +39,19 @@ public class InputPayManaOfCostPayment extends InputPayMana { // any mana tapabilities can't be used in payment as well as being tapped for convoke) handleConvokedCards(false); + + if (saPaidFor.isOffering()) { + handleOfferings(false); + } } - + @Override protected void onCancel() { handleConvokedCards(true); + + if (saPaidFor.isOffering()) { + handleOfferings(true); + } stop(); } diff --git a/src/main/java/forge/gui/input/InputPayManaSimple.java b/src/main/java/forge/gui/input/InputPayManaSimple.java index d554b2fc626..ef60a4fd9a5 100644 --- a/src/main/java/forge/gui/input/InputPayManaSimple.java +++ b/src/main/java/forge/gui/input/InputPayManaSimple.java @@ -92,12 +92,18 @@ public class InputPayManaSimple extends InputPayMana { handleConvokedCards(false); } + if (!this.saPaidFor.isOffering()) { + handleOfferings(false); + } } /** {@inheritDoc} */ @Override protected final void onCancel() { handleConvokedCards(true); + if (!this.saPaidFor.isOffering()) { + handleOfferings(true); + } player.getManaPool().refundManaPaid(this.saPaidFor, true); player.getZone(ZoneType.Battlefield).updateObservers(); // DO