As the title says, I'm trying to fix the implementations of
Urge to Feed and
Jaddi Lifestrider. At the moment the tapping is targeted and in the case of the Urge, the spell can't be played at all if the activating player has no vampires.
So I set up something similar to untapUpTo with a few small changes.
- Code in AbilityFactoryPermanentState.tapResolve | Open
- Code: Select all
if (params.containsKey("TapUpTo")) {
AbilityFactoryPermanentState.tapChooseUpTo(af, sa, params, remTapped);
} else {
// existing resolve code
}
}
/**
* <p>
* tapChooseUpTo.
* </p>
*
* @param af
* a {@link forge.card.abilityfactory.AbilityFactory} object.
* @param sa
* a {@link forge.card.spellability.SpellAbility} object.
* @param params
* a {@link java.util.HashMap} object.
* @param remTapped
* a {@link java.util.HashMap} object.
*/
private static void tapChooseUpTo(final AbilityFactory af, final SpellAbility sa,
final HashMap<String, String> params, final boolean remTapped) {
final Card card = sa.getSourceCard();
final int num = !params.get("TapUpTo").matches("[0-9][0-9]?") ? CardFactoryUtil.xCount(card,
card.getSVar(params.get("TapUpTo"))) : Integer.parseInt(params.get("TapUpTo"));
final String valid = params.get("ValidChoices");
final ArrayList<Player> definedPlayers = AbilityFactory.getDefinedPlayers(sa.getSourceCard(),
params.get("Defined"), sa);
CardList list = AllZoneUtil.getCardsIn(ZoneType.Battlefield);
list = list.getValidCards(valid, card.getController(), card);
list = list.filter(CardListFilter.UNTAPPED);
for (final Player p : definedPlayers) {
if (p.isHuman()) {
if (!list.isEmpty()) {
AllZone.getInputControl().setInput(CardFactoryUtil.inputTapUpToNValid(num, valid, sa, params, remTapped));
}
} else {
int count = 0;
while ((list.size() != 0) && (count < num)) {
for (int i = 0; (i < list.size()) && (count < num); i++) {
final Card c = CardFactoryUtil.getWorstAI(list);
if (c.isUntapped() && (remTapped)) {
card.addRemembered(c);
}
c.tap();
list.remove(c);
count++;
}
}
}
}
}
- Code in CardFactoryUtil | Open
- Code: Select all
/**
* <p>
* inputTapUpToNValid.
* </p>
* @param n
* a int.
* @param valid
* a {@link java.lang.String} object.
* @param sa
* a {@link forge.card.spellability.SpellAbility} object.
* @param params
* a {@link java.util.HashMap} object.
* @param remTapped
* a boolean.
* @return a {@link forge.control.input.Input} object.
*/
public static Input inputTapUpToNValid(final int n, final String valid, final SpellAbility sa,
final HashMap<String, String> params, final boolean remTapped) {
final Card card = sa.getSourceCard();
final String choices = (params.get("ValidDesc") != "") ? params.get("ValidDesc") : params.get("ValidChoices");
final Input tap = new Input() {
private static final long serialVersionUID = 1L;
private final int stop = n;
private int count = 0;
private CardList refund = new CardList();
@Override
public void showMessage() {
final StringBuilder sb = new StringBuilder();
sb.append("Select a ").append(choices).append(" to tap");
CMatchUI.SINGLETON_INSTANCE.showMessage(sb.toString());
ButtonUtil.enableAll();
}
@Override
public void selectButtonCancel() {
for (final Card undo : refund) {
undo.untap();
}
if (remTapped) {
card.clearRemembered();
}
this.stop();
}
@Override
public void selectButtonOK() {
this.stop();
}
@Override
public void selectCard(final Card c, final PlayerZone zone) {
if (c.isValid(valid, card.getController(), card) && zone.is(ZoneType.Battlefield) && c.isUntapped()) {
if (remTapped) {
card.addRemembered(c);
}
c.tap();
this.refund.add(c);
this.count++;
if (this.count == this.stop) {
this.stop();
}
}
} // selectCard()
};
return tap;
}
Everything is good except for one major problem: when you select the valid cards to tap, the rest of the spell finishes resolving. This means that the cards aren't remembered before the subabilities resolve. I tried adding freezeStack() and some similar functions before the setInput with the corresponding unfreezeStack etc afterwards, but none of what I tried worked.
How do I get the stack to stop resolving while the input is made, then resume resolving the subabilities. I've already got the stack description working nicely as well, so it's just this main function I need help with.
The corresponding script for
Urge to Feed is this:
- Urge to Feed | Open
- Code: Select all
Name:Urge to Feed
ManaCost:B B
Types:Instant
Text:no text
A:SP$ Pump | Cost$ B B | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumAtt$ -3 | NumDef$ -3 | IsCurse$ True | SubAbility$ VampiricUrge | SpellDescription$ Target creature gets -3/-3 until end of turn. You may tap any number of untapped Vampire creatures you control. If you do, put a +1/+1 counter on each of those Vampires.
SVar:VampiricUrge:DB$ Tap | TapUpTo$ AbleToFeedX | References$ AbleToFeedX | ValidChoices$ Creature.Vampire+untapped+YouCtrl | ValidDesc$ untapped Vampire creature you control | RememberTapped$ True | SubAbility$ VampiricFeed
SVar:VampiricFeed:DB$ PutCounter | CounterType$ P1P1 | CounterNum$ 1 | Defined$ Remembered | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:AbleToFeedX:Count$Valid Creature.Vampire+untapped+YouCtrl
SVar:Rarity:Uncommon
SVar:Picture:http://www.wizards.com/global/images/magic/general/urge_to_feed.jpg
SetInfo:WWK|Uncommon|http://magiccards.info/scans/en/wwk/70.jpg
Oracle:Target creature gets -3/-3 until end of turn. You may tap any number of untapped Vampire creatures you control. If you do, put a +1/+1 counter on each of those Vampires.
End