mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-11 08:16:23 +00:00
Initial checkin for Waterbending (#9120)
This commit is contained in:
@@ -1345,9 +1345,7 @@ public class ComputerUtilMana {
|
||||
}
|
||||
}
|
||||
|
||||
if (!effect) {
|
||||
CostAdjustment.adjust(manaCost, sa, null, test);
|
||||
}
|
||||
CostAdjustment.adjust(manaCost, sa, null, test, effect);
|
||||
|
||||
if ("NumTimes".equals(sa.getParam("Announce"))) { // e.g. the Adversary cycle
|
||||
ManaCost mkCost = sa.getPayCosts().getTotalMana();
|
||||
@@ -1773,15 +1771,18 @@ public class ComputerUtilMana {
|
||||
|
||||
/**
|
||||
* Matches list of creatures to shards in mana cost for convoking.
|
||||
* @param cost cost of convoked ability
|
||||
* @param list creatures to be evaluated
|
||||
* @param improvise
|
||||
*
|
||||
* @param cost cost of convoked ability
|
||||
* @param list creatures to be evaluated
|
||||
* @param artifacts
|
||||
* @param creatures
|
||||
* @return map between creatures and shards to convoke
|
||||
*/
|
||||
public static Map<Card, ManaCostShard> getConvokeOrImproviseFromList(final ManaCost cost, List<Card> list, boolean improvise) {
|
||||
public static Map<Card, ManaCostShard> getConvokeOrImproviseFromList(final ManaCost cost, List<Card> list, boolean artifacts, boolean creatures) {
|
||||
final Map<Card, ManaCostShard> convoke = new HashMap<>();
|
||||
Card convoked = null;
|
||||
if (!improvise) {
|
||||
if (creatures && !artifacts) {
|
||||
// Run for convoke but not improvise or waterbending
|
||||
for (ManaCostShard toPay : cost) {
|
||||
if (toPay.isSnow() || toPay.isColorless()) {
|
||||
continue;
|
||||
|
||||
@@ -1382,7 +1382,7 @@ public class PlayerControllerAi extends PlayerController {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Card, ManaCostShard> chooseCardsForConvokeOrImprovise(SpellAbility sa, ManaCost manaCost, CardCollectionView untappedCards, boolean improvise) {
|
||||
public Map<Card, ManaCostShard> chooseCardsForConvokeOrImprovise(SpellAbility sa, ManaCost manaCost, CardCollectionView untappedCards, boolean artifacts, boolean creatures, Integer maxReduction) {
|
||||
final Player ai = sa.getActivatingPlayer();
|
||||
final PhaseHandler ph = ai.getGame().getPhaseHandler();
|
||||
//Filter out mana sources that will interfere with payManaCost()
|
||||
@@ -1390,9 +1390,10 @@ public class PlayerControllerAi extends PlayerController {
|
||||
|
||||
// Filter out creatures if AI hasn't attacked yet
|
||||
if (ph.isPlayerTurn(ai) && ph.getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS)) {
|
||||
if (improvise) {
|
||||
if (!creatures) {
|
||||
untapped = CardLists.filter(untapped, c -> !c.isCreature());
|
||||
} else {
|
||||
// TODO AI needs to learn how to use Convoke or Waterbend
|
||||
return new HashMap<>();
|
||||
}
|
||||
}
|
||||
@@ -1406,13 +1407,16 @@ public class PlayerControllerAi extends PlayerController {
|
||||
if (!ai.getGame().getStack().isEmpty()) {
|
||||
final List<GameObject> objects = ComputerUtil.predictThreatenedObjects(sa.getActivatingPlayer(), null);
|
||||
for (Card c : blockers) {
|
||||
if (objects.contains(c) && (!improvise || c.isArtifact())) {
|
||||
if (objects.contains(c) && (creatures || c.isArtifact())) {
|
||||
untapped.add(c);
|
||||
}
|
||||
if (maxReduction != null && untapped.size() >= maxReduction) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ComputerUtilMana.getConvokeOrImproviseFromList(manaCost, untapped, improvise);
|
||||
return ComputerUtilMana.getConvokeOrImproviseFromList(manaCost, untapped, artifacts, creatures);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -15,6 +15,7 @@ import forge.game.*;
|
||||
import forge.game.ability.AbilityFactory.AbilityRecordType;
|
||||
import forge.game.card.*;
|
||||
import forge.game.cost.Cost;
|
||||
import forge.game.cost.CostAdjustment;
|
||||
import forge.game.cost.IndividualCostPaymentInstance;
|
||||
import forge.game.keyword.Keyword;
|
||||
import forge.game.keyword.KeywordInterface;
|
||||
@@ -1527,6 +1528,7 @@ public class AbilityUtils {
|
||||
else {
|
||||
cost = new Cost(unlessCost, true);
|
||||
}
|
||||
cost = CostAdjustment.adjust(cost, sa, true);
|
||||
return cost;
|
||||
}
|
||||
|
||||
|
||||
@@ -188,6 +188,15 @@ public class Cost implements Serializable {
|
||||
return this.isAbility;
|
||||
}
|
||||
|
||||
public final String getMaxWaterbend() {
|
||||
for (CostPart cp : this.costParts) {
|
||||
if (cp instanceof CostPartMana) {
|
||||
return ((CostPartMana) cp).getMaxWaterbend();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Cost() {
|
||||
|
||||
}
|
||||
@@ -564,6 +573,11 @@ public class Cost implements Serializable {
|
||||
return new CostRevealChosen(splitStr[0], splitStr.length > 1 ? splitStr[1] : null);
|
||||
}
|
||||
|
||||
if (parse.startsWith("Waterbend<")) {
|
||||
final String[] splitStr = abCostParse(parse, 1);
|
||||
return new CostWaterbend(splitStr[0]);
|
||||
}
|
||||
|
||||
if (parse.equals("Forage")) {
|
||||
return new CostForage();
|
||||
}
|
||||
@@ -973,6 +987,7 @@ public class Cost implements Serializable {
|
||||
} else {
|
||||
costParts.add(0, new CostPartMana(manaCost.toManaCost(), null));
|
||||
}
|
||||
getCostMana().setMaxWaterbend(mPart.getMaxWaterbend());
|
||||
} else if (part instanceof CostPutCounter || (mergeAdditional && // below usually not desired because they're from different causes
|
||||
(part instanceof CostDiscard || part instanceof CostDraw ||
|
||||
part instanceof CostAddMana || part instanceof CostPayLife ||
|
||||
|
||||
@@ -31,11 +31,13 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class CostAdjustment {
|
||||
|
||||
public static Cost adjust(final Cost cost, final SpellAbility sa, boolean effect) {
|
||||
if (sa.isTrigger() || cost == null || effect) {
|
||||
sa.setMaxWaterbend(cost);
|
||||
return cost;
|
||||
}
|
||||
|
||||
@@ -99,6 +101,9 @@ public class CostAdjustment {
|
||||
host.setState(CardStateName.Original, false);
|
||||
host.setFaceDown(false);
|
||||
}
|
||||
|
||||
sa.setMaxWaterbend(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -171,21 +176,22 @@ public class CostAdjustment {
|
||||
|
||||
// If cardsToDelveOut is null, will immediately exile the delved cards and remember them on the host card.
|
||||
// Otherwise, will return them in cardsToDelveOut and the caller is responsible for doing the above.
|
||||
public static boolean adjust(ManaCostBeingPaid cost, final SpellAbility sa, CardCollection cardsToDelveOut, boolean test) {
|
||||
if (sa.isTrigger() || sa.isReplacementAbility()) {
|
||||
public static boolean adjust(ManaCostBeingPaid cost, final SpellAbility sa, CardCollection cardsToDelveOut, boolean test, boolean effect) {
|
||||
if (effect) {
|
||||
adjustCostByWaterbend(cost, sa, test);
|
||||
}
|
||||
if (effect || sa.isTrigger() || sa.isReplacementAbility()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final Game game = sa.getActivatingPlayer().getGame();
|
||||
final Card originalCard = sa.getHostCard();
|
||||
boolean isStateChangeToFaceDown = false;
|
||||
|
||||
if (sa.isSpell()) {
|
||||
if (sa.isCastFaceDown() && !originalCard.isFaceDown()) {
|
||||
// Turn face down to apply cost modifiers correctly
|
||||
originalCard.turnFaceDownNoUpdate();
|
||||
isStateChangeToFaceDown = true;
|
||||
}
|
||||
boolean isStateChangeToFaceDown = false;
|
||||
if (sa.isSpell() && sa.isCastFaceDown() && !originalCard.isFaceDown()) {
|
||||
// Turn face down to apply cost modifiers correctly
|
||||
originalCard.turnFaceDownNoUpdate();
|
||||
isStateChangeToFaceDown = true;
|
||||
}
|
||||
|
||||
CardCollection cardsOnBattlefield = new CardCollection(game.getCardsIn(ZoneType.Battlefield));
|
||||
@@ -278,17 +284,19 @@ public class CostAdjustment {
|
||||
table.triggerChangesZoneAll(game, sa);
|
||||
}
|
||||
if (sa.getHostCard().hasKeyword(Keyword.CONVOKE)) {
|
||||
adjustCostByConvokeOrImprovise(cost, sa, false, test);
|
||||
adjustCostByConvokeOrImprovise(cost, sa, false, true, test);
|
||||
}
|
||||
if (sa.getHostCard().hasKeyword(Keyword.IMPROVISE)) {
|
||||
adjustCostByConvokeOrImprovise(cost, sa, true, test);
|
||||
adjustCostByConvokeOrImprovise(cost, sa, true, false, test);
|
||||
}
|
||||
} // isSpell
|
||||
|
||||
if (sa.hasParam("TapCreaturesForMana")) {
|
||||
adjustCostByConvokeOrImprovise(cost, sa, false, test);
|
||||
adjustCostByConvokeOrImprovise(cost, sa, false, true, test);
|
||||
}
|
||||
|
||||
adjustCostByWaterbend(cost, sa, test);
|
||||
|
||||
// Reset card state (if changed)
|
||||
if (isStateChangeToFaceDown) {
|
||||
originalCard.setFaceDown(false);
|
||||
@@ -299,6 +307,13 @@ public class CostAdjustment {
|
||||
}
|
||||
// GetSpellCostChange
|
||||
|
||||
private static void adjustCostByWaterbend(ManaCostBeingPaid cost, SpellAbility sa, boolean test) {
|
||||
Integer maxWaterbend = sa.getMaxWaterbend();
|
||||
if (maxWaterbend != null && maxWaterbend > 0) {
|
||||
adjustCostByConvokeOrImprovise(cost, sa, true, true, test);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean adjustCostByAssist(ManaCostBeingPaid cost, final SpellAbility sa, boolean test) {
|
||||
// 702.132a Assist is a static ability that modifies the rules of paying for the spell with assist (see rules 601.2g-h).
|
||||
// If the total cost to cast a spell with assist includes a generic mana component, before you activate mana abilities while casting it, you may choose another player.
|
||||
@@ -321,27 +336,33 @@ public class CostAdjustment {
|
||||
return assistant.getController().helpPayForAssistSpell(cost, sa, genericLeft, requestedAmount);
|
||||
}
|
||||
|
||||
private static void adjustCostByConvokeOrImprovise(ManaCostBeingPaid cost, final SpellAbility sa, boolean improvise, boolean test) {
|
||||
if (!improvise) {
|
||||
private static void adjustCostByConvokeOrImprovise(ManaCostBeingPaid cost, final SpellAbility sa, boolean artifacts, boolean creatures, boolean test) {
|
||||
if (creatures && !artifacts) {
|
||||
sa.clearTappedForConvoke();
|
||||
}
|
||||
|
||||
final Player activator = sa.getActivatingPlayer();
|
||||
CardCollectionView untappedCards = CardLists.filter(activator.getCardsIn(ZoneType.Battlefield),
|
||||
CardPredicates.CAN_TAP);
|
||||
if (improvise) {
|
||||
|
||||
Integer maxReduction = null;
|
||||
if (artifacts && creatures) {
|
||||
maxReduction = sa.getMaxWaterbend();
|
||||
Predicate <Card> isArtifactOrCreature = card -> card.isArtifact() || card.isCreature();
|
||||
untappedCards = CardLists.filter(untappedCards, isArtifactOrCreature);
|
||||
} else if (artifacts) {
|
||||
untappedCards = CardLists.filter(untappedCards, CardPredicates.ARTIFACTS);
|
||||
} else {
|
||||
untappedCards = CardLists.filter(untappedCards, CardPredicates.CREATURES);
|
||||
}
|
||||
|
||||
Map<Card, ManaCostShard> convokedCards = activator.getController().chooseCardsForConvokeOrImprovise(sa,
|
||||
cost.toManaCost(), untappedCards, improvise);
|
||||
cost.toManaCost(), untappedCards, artifacts, creatures, maxReduction);
|
||||
|
||||
CardCollection tapped = new CardCollection();
|
||||
for (final Entry<Card, ManaCostShard> conv : convokedCards.entrySet()) {
|
||||
Card c = conv.getKey();
|
||||
if (!improvise) {
|
||||
if (creatures && !artifacts) {
|
||||
sa.addTappedForConvoke(c);
|
||||
}
|
||||
cost.decreaseShard(conv.getValue(), 1);
|
||||
|
||||
@@ -39,6 +39,8 @@ public class CostPartMana extends CostPart {
|
||||
private boolean isEnchantedCreatureCost = false;
|
||||
private boolean isCostPayAnyNumberOfTimes = false;
|
||||
|
||||
protected String maxWaterbend;
|
||||
|
||||
public int paymentOrder() { return shouldPayLast() ? 200 : 0; }
|
||||
|
||||
public boolean shouldPayLast() {
|
||||
@@ -63,6 +65,13 @@ public class CostPartMana extends CostPart {
|
||||
this.isEnchantedCreatureCost = enchantedCreatureCost;
|
||||
}
|
||||
|
||||
public String getMaxWaterbend() {
|
||||
return maxWaterbend;
|
||||
}
|
||||
public void setMaxWaterbend(String max) {
|
||||
maxWaterbend = max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the mana.
|
||||
*
|
||||
@@ -101,7 +110,7 @@ public class CostPartMana extends CostPart {
|
||||
public boolean isUndoable() { return true; }
|
||||
|
||||
@Override
|
||||
public final String toString() {
|
||||
public String toString() {
|
||||
return cost.toString();
|
||||
}
|
||||
|
||||
|
||||
18
forge-game/src/main/java/forge/game/cost/CostWaterbend.java
Normal file
18
forge-game/src/main/java/forge/game/cost/CostWaterbend.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package forge.game.cost;
|
||||
|
||||
import forge.card.mana.ManaCost;
|
||||
import forge.card.mana.ManaCostParser;
|
||||
|
||||
public class CostWaterbend extends CostPartMana {
|
||||
|
||||
public CostWaterbend(final String mana) {
|
||||
super(new ManaCost(new ManaCostParser(mana)), null);
|
||||
|
||||
maxWaterbend = mana;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String toString() {
|
||||
return "Waterbend " + getMana().toString();
|
||||
}
|
||||
}
|
||||
@@ -202,7 +202,7 @@ public abstract class PlayerController {
|
||||
public abstract CardCollection chooseCardsToDiscardToMaximumHandSize(int numDiscard);
|
||||
|
||||
public abstract CardCollectionView chooseCardsToDelve(int genericAmount, CardCollection grave);
|
||||
public abstract Map<Card, ManaCostShard> chooseCardsForConvokeOrImprovise(SpellAbility sa, ManaCost manaCost, CardCollectionView untappedCards, boolean improvise);
|
||||
public abstract Map<Card, ManaCostShard> chooseCardsForConvokeOrImprovise(SpellAbility sa, ManaCost manaCost, CardCollectionView untappedCards, boolean artifacts, boolean creatures, Integer maxReduction);
|
||||
public abstract List<Card> chooseCardsForSplice(SpellAbility sa, List<Card> cards);
|
||||
|
||||
public abstract CardCollectionView chooseCardsToRevealFromHand(int min, int max, CardCollectionView valid);
|
||||
|
||||
@@ -144,6 +144,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
private final Supplier<CardCollection> tappedForConvoke = Suppliers.memoize(CardCollection::new);
|
||||
private Card sacrificedAsOffering;
|
||||
private Card sacrificedAsEmerge;
|
||||
private Integer maxWaterbend;
|
||||
|
||||
private AbilityManaPart manaPart;
|
||||
|
||||
@@ -2692,4 +2693,14 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getMaxWaterbend() {
|
||||
return maxWaterbend;
|
||||
}
|
||||
public void setMaxWaterbend(Cost cost) {
|
||||
if (cost == null || cost.getMaxWaterbend() == null) {
|
||||
return;
|
||||
}
|
||||
maxWaterbend = AbilityUtils.calculateAmount(getHostCard(), cost.getMaxWaterbend(), this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -428,6 +428,10 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
||||
game.getTriggerHandler().runTrigger(TriggerType.AbilityCast, runParams, true);
|
||||
}
|
||||
|
||||
if (sp.getPayCosts() != null && sp.getMaxWaterbend() != null) {
|
||||
activator.triggerElementalBend(TriggerType.Waterbend);
|
||||
}
|
||||
|
||||
// Run Cycled triggers
|
||||
if (sp.isCycling()) {
|
||||
activator.addCycled(sp);
|
||||
|
||||
@@ -690,7 +690,7 @@ public class PlayerControllerForTests extends PlayerController {
|
||||
|
||||
@Override
|
||||
public Map<Card, ManaCostShard> chooseCardsForConvokeOrImprovise(SpellAbility sa, ManaCost manaCost,
|
||||
CardCollectionView untappedCards, boolean improvise) {
|
||||
CardCollectionView untappedCards, boolean artifacts, boolean creatures, Integer maxReduction) {
|
||||
// TODO: AI to choose a creature to tap would go here
|
||||
// Probably along with deciding how many creatures to tap
|
||||
return new HashMap<>();
|
||||
|
||||
8
forge-gui/res/cardsfolder/upcoming/geyser_leaper.txt
Normal file
8
forge-gui/res/cardsfolder/upcoming/geyser_leaper.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
Name:Geyser Leaper
|
||||
ManaCost:4 U
|
||||
Types:Creature Human Warrior Ally
|
||||
PT:4/3
|
||||
K:Flying
|
||||
A:AB$ Draw | Cost$ Waterbend<4> | NumCards$ 1 | SubAbility$ DBDiscard | SpellDescription$ Draw a card, then discard a card. (While paying a waterbend cost, you can tap your artifacts and creatures to help. Each one pays for {1}.)
|
||||
SVar:DBDiscard:DB$ Discard | Defined$ You | NumCards$ 1 | Mode$ TgtChoose
|
||||
Oracle:Flying\nWaterbend 4: Draw a card, then discard a card.
|
||||
@@ -0,0 +1,9 @@
|
||||
Name:Ruinous Waterbending
|
||||
ManaCost:1 B B
|
||||
Types:Sorcery Lesson
|
||||
S:Mode$ OptionalCost | EffectZone$ All | ValidCard$ Card.Self | ValidSA$ Spell | Cost$ Waterbend<4> | Description$ As an additional cost to cast this spell, you may waterbend {4}. (While paying a waterbend cost, you can tap your artifacts and creatures to help. Each one pays for {1}.)
|
||||
A:SP$ PumpAll | ValidCards$ Creature | NumAtt$ -2 | NumDef$ -2 | IsCurse$ True | SubAbility$ DBEffect | SpellDescription$ All creatures get -2/-2 until end of turn. If this spell’s additional cost was paid, whenever a creature dies this turn, you gain 1 life.
|
||||
SVar:DBEffect:DB$ Effect | Triggers$ TrigDies | Condition$ OptionalCost | ConditionOptionalPaid$ True
|
||||
SVar:TrigDies:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Creature | Execute$ TrigGainLife | TriggerDescription$ Whenever a creature dies this turn, you gain 1 life.
|
||||
SVar:TrigGainLife:DB$ GainLife | LifeAmount$ 1
|
||||
Oracle:As an additional cost to cast this spell, you may waterbend {4}. (While paying a waterbend cost, you can tap your artifacts and creatures to help. Each one pays for {1}.)\nAll creatures get -2/-2 until end of turn. If this spell’s additional cost was paid, whenever a creature dies this turn, you gain 1 life.
|
||||
@@ -0,0 +1,10 @@
|
||||
Name:Waterbender's Restoration
|
||||
ManaCost:U U
|
||||
Types:Instant Lesson
|
||||
S:Mode$ RaiseCost | ValidCard$ Card.Self | Activator$ You | Type$ Spell | Cost$ Waterbend<X> | EffectZone$ All | Description$ As an additional cost to cast this spell, waterbend {X}. (While paying a waterbend cost, you can tap your artifacts and creatures to help. Each one pays for {1}.)
|
||||
A:SP$ ChangeZone | ValidTgts$ Creature.YouCtrl | Announce$ X | TargetMin$ X | TargetMax$ X | Origin$ Battlefield | Destination$ Exile | TgtPrompt$ Select target creature you control | SubAbility$ DelTrig | RememberChanged$ True | SpellDescription$ Exile X target creatures you control. Return those cards to the battlefield under their owner’s control at the beginning of the next end step.
|
||||
SVar:DelTrig:DB$ DelayedTrigger | Mode$ Phase | Phase$ End of Turn | Execute$ TrigReturn | RememberObjects$ RememberedLKI | TriggerDescription$ Return exiled permanent to the battlefield. | SubAbility$ DBCleanup
|
||||
SVar:TrigReturn:DB$ ChangeZone | Origin$ Exile | Destination$ Battlefield | Defined$ DelayTriggerRememberedLKI
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
SVar:X:Count$xPaid
|
||||
Oracle:As an additional cost to cast this spell, waterbend {X}. (While paying a waterbend cost, you can tap your artifacts and creatures to help. Each one pays for {1}.)\nExile X target creatures you control. Return those cards to the battlefield under their owner’s control at the beginning of the next end step.
|
||||
@@ -0,0 +1,7 @@
|
||||
Name:Waterbending Lesson
|
||||
ManaCost:3 U
|
||||
Types:Sorcery Lesson
|
||||
A:SP$ Draw | NumCards$ 3 | SubAbility$ DBDiscard | SpellDescription$ Draw three cards. Then discard a card unless you waterbend {2}. (While paying a waterbend cost, you can tap your artifacts and creatures to help. Each one pays for {1}.)
|
||||
SVar:DBDiscard:DB$ Discard | Defined$ You | NumCards$ 1 | Mode$ TgtChoose | UnlessCost$ Waterbend<2> | UnlessPayer$ You
|
||||
DeckHas:Ability$Discard
|
||||
Oracle:Draw three cards. Then discard a card unless you waterbend {2}. (While paying a waterbend cost, you can tap your artifacts and creatures to help. Each one pays for {1}.)
|
||||
@@ -27,18 +27,33 @@ public final class InputSelectCardsForConvokeOrImprovise extends InputSelectMany
|
||||
private final ManaCostBeingPaid remainingCost;
|
||||
private final Player player;
|
||||
private final CardCollectionView availableCards;
|
||||
private final boolean improvise;
|
||||
private final boolean artifacts;
|
||||
private final boolean creatures;
|
||||
private final Integer maxSelectable;
|
||||
private final String cardType;
|
||||
private final String description;
|
||||
|
||||
public InputSelectCardsForConvokeOrImprovise(final PlayerControllerHuman controller, final Player p, final ManaCost cost, final CardCollectionView untapped, boolean impr, final SpellAbility sa) {
|
||||
public InputSelectCardsForConvokeOrImprovise(final PlayerControllerHuman controller, final Player p, final SpellAbility sa, final ManaCost cost, final CardCollectionView untapped, boolean artifacts, boolean creatures, Integer maxReduction) {
|
||||
super(controller, 0, Math.min(cost.getCMC(), untapped.size()), sa);
|
||||
remainingCost = new ManaCostBeingPaid(cost);
|
||||
player = p;
|
||||
availableCards = untapped;
|
||||
improvise = impr;
|
||||
cardType = impr ? "artifact" : "creature";
|
||||
description = impr ? "Improvise" : "Convoke";
|
||||
this.artifacts = artifacts;
|
||||
this.creatures = creatures;
|
||||
this.maxSelectable = maxReduction;
|
||||
|
||||
if (artifacts && creatures) {
|
||||
cardType = "artifact or creature";
|
||||
description = "Waterbend";
|
||||
} else if (!artifacts && !creatures) {
|
||||
throw new IllegalArgumentException("At least one of artifacts or creatures must be true");
|
||||
} else if (creatures) {
|
||||
cardType = "creature";
|
||||
description = "Convoke";
|
||||
} else {
|
||||
cardType = "artifact";
|
||||
description = "Improvise";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -49,6 +64,10 @@ public final class InputSelectCardsForConvokeOrImprovise extends InputSelectMany
|
||||
sb.append(sa.getStackDescription()).append("\n");
|
||||
}
|
||||
sb.append(TextUtil.concatNoSpace("Choose ", cardType, " to tap for ", description, ".\nRemaining mana cost is ", remainingCost.toString()));
|
||||
|
||||
if (maxSelectable != null) {
|
||||
sb.append(". You may select up to ").append(chosenCards.size() - maxSelectable).append(" more ").append(cardType).append("(s).");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@@ -66,10 +85,17 @@ public final class InputSelectCardsForConvokeOrImprovise extends InputSelectMany
|
||||
onSelectStateChanged(card, false);
|
||||
}
|
||||
else {
|
||||
if (maxSelectable != null && chosenCards.size() >= maxSelectable) {
|
||||
// Should show a different message if there's a max selectable
|
||||
return false;
|
||||
}
|
||||
|
||||
byte chosenColor;
|
||||
if (improvise) {
|
||||
if (artifacts) {
|
||||
// Waterbend/Improvise can be paid with colorless mana from artifacts
|
||||
chosenColor = ManaCostShard.COLORLESS.getColorMask();
|
||||
} else {
|
||||
// Convoke can pay color or generic mana cost from creatures
|
||||
ColorSet colors = card.getColor();
|
||||
if (colors.isMulticolor()) {
|
||||
//if card is multicolor, strip out any colors which can't be paid towards remaining cost
|
||||
@@ -107,10 +133,6 @@ public final class InputSelectCardsForConvokeOrImprovise extends InputSelectMany
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPlayerSelected(final Player player, final ITriggerEvent triggerEvent) {
|
||||
}
|
||||
|
||||
public Map<Card, ManaCostShard> getConvokeMap() {
|
||||
if (hasCancelled()) {
|
||||
return Maps.newHashMap();
|
||||
|
||||
@@ -560,9 +560,7 @@ public class HumanPlay {
|
||||
}
|
||||
|
||||
CardCollection cardsToDelve = new CardCollection();
|
||||
if (!effect) {
|
||||
CostAdjustment.adjust(toPay, ability, cardsToDelve, false);
|
||||
}
|
||||
CostAdjustment.adjust(toPay, ability, cardsToDelve, false, effect);
|
||||
|
||||
Card offering = null;
|
||||
Card emerge = null;
|
||||
|
||||
@@ -2332,9 +2332,9 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
||||
|
||||
@Override
|
||||
public Map<Card, ManaCostShard> chooseCardsForConvokeOrImprovise(final SpellAbility sa, final ManaCost manaCost,
|
||||
final CardCollectionView untappedCards, boolean improvise) {
|
||||
final CardCollectionView untappedCards, boolean artifacts, boolean creatures, Integer maxReduction) {
|
||||
final InputSelectCardsForConvokeOrImprovise inp = new InputSelectCardsForConvokeOrImprovise(this, player,
|
||||
manaCost, untappedCards, improvise, sa);
|
||||
sa, manaCost, untappedCards, artifacts, creatures, maxReduction);
|
||||
inp.showAndWait();
|
||||
return inp.getConvokeMap();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user