simultaneous announces for X and multikicker work now.

Comet storm scripted, Strength of Tajuru scriptable.
possible side effect: AI can may become unable to cast spells with X in their cost. (see ComputerUtilMana.java:242)
This commit is contained in:
Maxmtg
2013-04-03 20:59:31 +00:00
parent d4d19f4f65
commit e3eb4dd972
12 changed files with 78 additions and 128 deletions

View File

@@ -4470,26 +4470,10 @@ public class Card extends GameEntity implements Comparable<Card> {
public final void addMultiKickerMagnitude(final int n) {
this.multiKickerMagnitude += n;
}
/**
* <p>
* Setter for the field <code>multiKickerMagnitude</code>.
* </p>
*
* @param n
* a int.
*/
public final void setMultiKickerMagnitude(final int n) {
this.multiKickerMagnitude = n;
}
/**
* <p>
* Getter for the field <code>multiKickerMagnitude</code>.
* </p>
*
* @return a int.
*/
public final int getMultiKickerMagnitude() {
return this.multiKickerMagnitude;
}

View File

@@ -316,7 +316,6 @@ public class CardFactoryCreatures {
c.addCounter(CounterType.P1P1, xCounters, true);
}
};
spell.setXManaCost(1);
// Do not remove SpellAbilities created by AbilityFactory or
// Keywords.
card.clearFirstSpell();

View File

@@ -47,7 +47,6 @@ import forge.card.ability.ApiType;
import forge.card.cost.Cost;
import forge.card.mana.ManaCost;
import forge.card.mana.ManaCostParser;
import forge.card.mana.ManaCostShard;
import forge.card.replacement.ReplacementEffect;
import forge.card.replacement.ReplacementHandler;
import forge.card.replacement.ReplacementLayer;
@@ -2509,12 +2508,6 @@ public class CardFactoryUtil {
}
} // Suspend
int xCount = card.getManaCost().getShardCount(ManaCostShard.X);
if (xCount > 0) {
final SpellAbility sa = card.getSpellAbility()[0];
sa.setXManaCost(xCount);
} // X
if (CardFactoryUtil.hasKeyword(card, "Fading") != -1) {
final int n = CardFactoryUtil.hasKeyword(card, "Fading");
if (n != -1) {

View File

@@ -124,6 +124,12 @@ public class CostPartMana extends CostPart {
byte xColor = MagicColor.fromName(ability.hasParam("XColor") ? ability.getParam("XColor") : "1");
toPay.increaseShard(ManaCostShard.valueOf(xColor), xCost);
}
int timesMultikicked = ability.getSourceCard().getMultiKickerMagnitude();
if ( timesMultikicked > 0 && ability.isAnnouncing("Multikicker")) {
ManaCost mkCost = ability.getMultiKickerManaCost();
for(int i = 0; i < timesMultikicked; i++)
toPay.combineManaCost(mkCost);
}
if (!toPay.isPaid()) {

View File

@@ -155,11 +155,20 @@ public class HumanPlaySpellAbility {
String announce = ability.getParam("Announce");
if (announce != null) {
for(String aVar : announce.split(",")) {
Integer value = ability.getActivatingPlayer().getController().announceRequirements(ability, aVar, ability.getPayCosts().getCostMana().canXbe0());
String varName = aVar.trim();
boolean allowZero = !("X".equalsIgnoreCase(varName)) || ability.getPayCosts().getCostMana().canXbe0();
Integer value = ability.getActivatingPlayer().getController().announceRequirements(ability, varName, allowZero);
if ( null == value )
return false;
ability.setSVar(aVar, value.toString());
ability.getSourceCard().setSVar(aVar, value.toString());
ability.setSVar(varName, value.toString());
if( "Multikicker".equals(varName) ) {
ability.getSourceCard().setMultiKickerMagnitude(value);
} else {
ability.getSourceCard().setSVar(varName, value.toString());
}
}
}
return true;

View File

@@ -57,7 +57,6 @@ public abstract class SpellAbility implements ISpellAbility {
private ManaCost manaCost = null;
private ManaCost multiKickerManaCost = null;
private ManaCost replicateManaCost = null;
private int xManaCost = 0;
private Player activatingPlayer = null;
private String type = "Intrinsic"; // set to Intrinsic by default
@@ -290,29 +289,6 @@ public abstract class SpellAbility implements ISpellAbility {
this.replicateManaCost = spellManaCost;
}
/**
* <p>
* Getter for the field <code>xManaCost</code>.
* </p>
*
* @return a {@link java.lang.String} object.
*/
public int getXManaCost() {
return this.xManaCost;
}
/**
* <p>
* Setter for the field <code>xManaCost</code>.
* </p>
*
* @param cost
* a {@link java.lang.String} object.
*/
public final void setXManaCost(final int cost) {
this.xManaCost = cost;
}
/**
* <p>
* Getter for the field <code>activatingPlayer</code>.
@@ -396,7 +372,7 @@ public abstract class SpellAbility implements ISpellAbility {
* @return a boolean.
*/
public boolean isMultiKicker() {
return this.multiKickerManaCost != null;
return this.multiKickerManaCost != null && !this.isAnnouncing("Multikicker");
}
/**
@@ -423,17 +399,6 @@ public abstract class SpellAbility implements ISpellAbility {
}
/**
* <p>
* isXCost.
* </p>
*
* @return a boolean.
*/
public boolean isXCost() {
return getXManaCost() > 0;
}
/**
* <p>
* setIsCycling.
@@ -1757,5 +1722,10 @@ public abstract class SpellAbility implements ISpellAbility {
return true;
}
return false;
}
public boolean isXCost() {
CostPartMana cm = payCosts != null ? getPayCosts().getCostMana() : null;
return cm != null && cm.getAmountOfX() > 0;
}
}

View File

@@ -219,11 +219,6 @@ public class WrappedAbility extends Ability implements ISpellAbility {
return sa.getTargetPlayer();
}
@Override
public int getXManaCost() {
return sa.getXManaCost();
}
@Override
public boolean isAbility() {
return sa.isAbility();

View File

@@ -62,6 +62,11 @@ public final class InputSelectTargets extends InputSyncronizedBase {
}
//sb.append(tgt.getTargetedString()).append("\n");
sb.append(tgt.getVTSelection());
int maxTargets = tgt.getMaxTargets(sa.getSourceCard(), sa);
int targeted = tgt.getNumTargeted();
if(maxTargets > 1)
sb.append("\n(").append(maxTargets - targeted).append(" more can be targeted)");
showMessage(sb.toString());

View File

@@ -16,12 +16,14 @@ import forge.Constant;
import forge.card.MagicColor;
import forge.card.ability.AbilityUtils;
import forge.card.ability.ApiType;
import forge.card.cardfactory.CardFactoryUtil;
import forge.card.cost.Cost;
import forge.card.cost.CostPayment;
import forge.card.mana.ManaCost;
import forge.card.mana.ManaCostBeingPaid;
import forge.card.mana.ManaCostShard;
import forge.card.mana.ManaPool;
import forge.card.spellability.Ability;
import forge.card.spellability.AbilityManaPart;
import forge.card.spellability.AbilitySub;
import forge.card.spellability.SpellAbility;
@@ -65,7 +67,7 @@ public class ComputerUtilMana {
manapool.clearManaPaid(sa, test);
return true;
}
// get map of mana abilities
final Map<String, List<SpellAbility>> manaAbilityMap = ComputerUtilMana.mapManaSources(ai, checkPlayable);
// initialize ArrayList list for mana needed
@@ -237,6 +239,22 @@ public class ComputerUtilMana {
} // payManaCost()
// TODO: this code is disconnected now, it was moved here from MagicStack, where X cost is not processed any more
public static void computerPayX(final SpellAbility sa, AIPlayer player, int xCost) {
final int neededDamage = CardFactoryUtil.getNeededXDamage(sa);
final Ability ability = new Ability(sa.getSourceCard(), ManaCost.get(xCost)) {
@Override
public void resolve() {
sa.getSourceCard().addXManaCostPaid(1);
}
};
while (ComputerUtilCost.canPayCost(ability, player) && (neededDamage != sa.getSourceCard().getXManaCostPaid())) {
ComputerUtil.playNoStack(player, ability, player.getGame());
}
}
/**
* <p>
* payManaCost.

View File

@@ -45,10 +45,8 @@ import forge.card.spellability.TargetChoices;
import forge.card.trigger.Trigger;
import forge.card.trigger.TriggerType;
import forge.control.input.InputPayManaExecuteCommands;
import forge.control.input.InputPayManaX;
import forge.control.input.InputSelectCards;
import forge.control.input.InputSelectCardsFromList;
import forge.control.input.InputSynchronized;
import forge.game.GameActionUtil;
import forge.game.GameState;
import forge.game.ai.ComputerUtil;
@@ -381,76 +379,37 @@ public class MagicStack extends MyObservable {
}
if (sp.getSourceCard().isCopiedSpell()) {
this.push(sp);
} else if (!sp.isMultiKicker() && !sp.isReplicate() && !sp.isXCost()) {
} else if (!sp.isMultiKicker() && !sp.isReplicate()) {
this.push(sp);
} else if ((sp.getPayCosts() != null) && !sp.isMultiKicker() && !sp.isReplicate()) {
this.push(sp);
} else if (sp.isXCost()) {
// TODO: convert any X costs to use abCost so it happens earlier
final SpellAbility sa = sp;
final int xCost = sa.getXManaCost();
Player player = sp.getSourceCard().getController();
if (player.isHuman()) {
InputSynchronized inp = new InputPayManaX(sa, xCost, true);
FThreads.setInputAndWait(inp);
MagicStack.this.push(sa);
} else {
// computer
final int neededDamage = CardFactoryUtil.getNeededXDamage(sa);
final Ability ability = new Ability(sp.getSourceCard(), ManaCost.get(xCost)) {
@Override
public void resolve() {
final Card crd = this.getSourceCard();
crd.addXManaCostPaid(1);
}
};
while (ComputerUtilCost.canPayCost(ability, player) && (neededDamage != sa.getSourceCard().getXManaCostPaid())) {
ComputerUtil.playNoStack((AIPlayer)player, ability, game);
}
this.push(sa);
}
} else if (sp.isMultiKicker()) {
// TODO: convert multikicker support in abCost so this doesn't
// happen here
// both X and multi is not supported yet
final SpellAbility sa = sp;
final Ability abilityIncreaseMultikicker = new Ability(sp.getSourceCard(), sp.getMultiKickerManaCost()) {
@Override
public void resolve() {
this.getSourceCard().addMultiKickerMagnitude(1);
}
};
final Player activating = sp.getActivatingPlayer();
if (activating.isHuman()) {
sa.getSourceCard().addMultiKickerMagnitude(-1);
final Runnable paidCommand = new Runnable() {
@Override
public void run() {
abilityIncreaseMultikicker.resolve();
int mkMagnitude = sa.getSourceCard().getMultiKickerMagnitude();
String prompt = String.format("Multikicker for %s\r\nTimes Kicked: %d\r\n", sa.getSourceCard(), mkMagnitude );
InputPayManaExecuteCommands toSet = new InputPayManaExecuteCommands(activating, prompt, sp.getMultiKickerManaCost());
FThreads.setInputAndWait(toSet);
if ( toSet.isPaid() ) {
this.run();
} else
MagicStack.this.push(sa);
}
};
paidCommand.run();
while(true) {
int mkMagnitude = sa.getSourceCard().getMultiKickerMagnitude();
String prompt = String.format("Multikicker for %s\r\nTimes Kicked: %d\r\n", sa.getSourceCard(), mkMagnitude );
InputPayManaExecuteCommands toSet = new InputPayManaExecuteCommands(activating, prompt, sp.getMultiKickerManaCost());
FThreads.setInputAndWait(toSet);
if ( !toSet.isPaid() )
break;
sa.getSourceCard().addMultiKickerMagnitude(1);
}
} else {
// computer
final Ability abilityIncreaseMultikicker = new Ability(sp.getSourceCard(), sp.getMultiKickerManaCost()) {
@Override
public void resolve() {
this.getSourceCard().addMultiKickerMagnitude(1);
}
};
while (ComputerUtilCost.canPayCost(abilityIncreaseMultikicker, activating)) {
ComputerUtil.playNoStack((AIPlayer)activating, abilityIncreaseMultikicker, game);
}
this.push(sa);
}
this.push(sa);
} else if (sp.isReplicate()) {
// TODO: convert multikicker/replicate support in abCost so this
// doesn't happen here