- Added War Cadence

- new preference for enabling/disabling the prompt for block costs of 0.
This commit is contained in:
moomarc
2013-08-06 17:39:37 +00:00
parent 44b4e699aa
commit c78689db89
8 changed files with 101 additions and 9 deletions

1
.gitattributes vendored
View File

@@ -12542,6 +12542,7 @@ res/cardsfolder/w/wanderwine_hub.txt svneol=native#text/plain
res/cardsfolder/w/wanderwine_prophets.txt svneol=native#text/plain
res/cardsfolder/w/waning_wurm.txt svneol=native#text/plain
res/cardsfolder/w/war_barge.txt -text svneol=unset#text/plain
res/cardsfolder/w/war_cadence.txt -text
res/cardsfolder/w/war_chariot.txt svneol=native#text/plain
res/cardsfolder/w/war_dance.txt svneol=native#text/plain
res/cardsfolder/w/war_elemental.txt -text

View File

@@ -0,0 +1,13 @@
Name:War Cadence
ManaCost:2 R
Types:Enchantment
A:AB$ StoreSVar | Cost$ X R | SVar$ PaidNum | Type$ Count | Expression$ xPaid | SubAbility$ CadenceEffect | AILogic$ RestrictBlocking | SpellDescription$ This turn, creatures can't block unless their controller pays X for each blocking creature he or she controls.
SVar:CadenceEffect:DB$ Effect | StaticAbilities$ CadenceStaticAb | SVars$ PaidNum | Stackable$ False | RememberObjects$ Valid Creature.blocking
SVar:CadenceStaticAb:Mode$ CantBlockUnless | ValidCard$ Card.IsNotRemembered | Cost$ PaidNum | References$ PaidNum | EffectZone$ Command | Description$ This turn, creatures can't block unless their controller pays X for each blocking creature he or she controls.
# According to the 10/4/2004 ruling: The ability only applies to blocks declared after it resolves. It will not add costs to any blockers already announced.
SVar:X:Count$xPaid
SVar:PaidNum:Number$0
SVar:NonStackingEffect:True
SVar:RemAIDeck:True
SVar:Picture:http://www.wizards.com/global/images/magic/general/war_cadence.jpg
Oracle:{X}{R}: This turn, creatures can't block unless their controller pays {X} for each blocking creature he or she controls.

View File

@@ -1,10 +1,21 @@
package forge.card.ability.ai;
import java.util.ArrayList;
import java.util.List;
import forge.Card;
import forge.CardLists;
import forge.CardPredicates.Presets;
import forge.card.ability.SpellAbilityAi;
import forge.card.spellability.SpellAbility;
import forge.game.Game;
import forge.game.ai.ComputerUtil;
import forge.game.ai.ComputerUtilCombat;
import forge.game.ai.ComputerUtilMana;
import forge.game.combat.Combat;
import forge.game.combat.CombatUtil;
import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType;
import forge.game.player.Player;
public class StoreSVarAi extends SpellAbilityAi {
@@ -14,7 +25,50 @@ public class StoreSVarAi extends SpellAbilityAi {
//Tree of Redemption
final Card source = sa.getSourceCard();
if (ComputerUtil.waitForBlocking(sa) || ai.getLife() + 1 >= source.getNetDefense()
final Game game = ai.getGame();
final Combat combat = game.getCombat();
final PhaseHandler ph = game.getPhaseHandler();
final Player opp = ai.getOpponents().get(0);
if (sa.hasParam("AILogic")) {
if (sa.getPayCosts().getTotalMana().countX() > 0 && source.getSVar("X").equals("Count$xPaid")) {
// Set PayX here to half the remaining mana to allow for Main 2 and other combat shenanigans.
final int xPay = ComputerUtilMana.determineLeftoverMana(sa, ai) / 2;
if (xPay == 0) { return false; }
source.setSVar("PayX", Integer.toString(xPay));
}
final String logic = sa.getParam("AILogic");
if (logic.equals("RestrictBlocking")) {
if (!ph.isPlayerTurn(ai) || ph.getPhase().isBefore(PhaseType.COMBAT_BEGIN)
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS)) {
return false;
}
List<Card> possibleAttackers = ai.getCreaturesInPlay();
List<Card> possibleBlockers = opp.getCreaturesInPlay();
possibleBlockers = CardLists.filter(possibleBlockers, Presets.UNTAPPED);
int oppLife = opp.getLife();
int potentialDmg = 0;
List<Card> currentAttackers = new ArrayList<Card>();
if (possibleBlockers.size() == 0) { return false; }
for (final Card creat : possibleAttackers) {
if (CombatUtil.canAttack(creat, opp) && possibleBlockers.size() > 1) {
potentialDmg += creat.getCurrentPower();
if (potentialDmg >= oppLife) { return true; }
}
if (combat != null && combat.isAttacking(creat)) {
currentAttackers.add(creat);
}
}
return currentAttackers.size() > possibleBlockers.size();
}
return false;
}
else if (ComputerUtil.waitForBlocking(sa) || ai.getLife() + 1 >= source.getNetDefense()
|| (ai.getLife() > 5 && !ComputerUtilCombat.lifeInSeriousDanger(ai, ai.getGame().getCombat()))) {
return false;
}

View File

@@ -664,19 +664,25 @@ public class PhaseHandler implements java.io.Serializable {
private static boolean payRequiredBlockCosts(Game game, Card blocker, Card attacker) {
Cost blockCost = new Cost(ManaCost.ZERO, true);
boolean hasBlockCost = false;
// Sort abilities to apply them in proper order
for (Card card : game.getCardsIn(ZoneType.Battlefield)) {
List<ZoneType> checkZones = ZoneType.listValueOf("Battlefield,Command");
for (Card card : game.getCardsIn(checkZones)) {
final ArrayList<StaticAbility> staticAbilities = card.getStaticAbilities();
for (final StaticAbility stAb : staticAbilities) {
Cost c1 = stAb.getBlockCost(blocker, attacker);
if ( c1 != null )
if ( c1 != null ) {
blockCost.add(c1);
hasBlockCost = true;
}
}
}
boolean hasPaid = blockCost.getTotalMana().isZero() && blockCost.isOnlyManaCost(); // true if needless to pay
boolean hasPaid = blockCost.getTotalMana().isZero() && blockCost.isOnlyManaCost() && (!hasBlockCost
|| Singletons.getModel().getPreferences().getPrefBoolean(FPref.MATCHPREF_PROMPT_FREE_BLOCKS)); // true if needless to pay
if (!hasPaid) {
hasPaid = blocker.getController().getController().payManaOptional(blocker, blockCost, null, "Pay cost to declare " + blocker + " a blocker", ManaPaymentPurpose.DeclareBlocker);
hasPaid = blocker.getController().getController().payManaOptional(blocker, blockCost, null, "Pay cost to declare " + blocker + " a blocker. ", ManaPaymentPurpose.DeclareBlocker);
}
return hasPaid;
}

View File

@@ -302,10 +302,16 @@ public class HumanPlay {
costPart = parts.get(0);
}
final String orString = prompt != null ? "" : " (or: " + sourceAbility.getStackDescription() + ")";
if (parts.isEmpty() || costPart.getAmount().equals("0")) {
return GuiDialog.confirm(source, "Do you want to pay 0?" + orString);
}
// 0 mana costs were slipping through because CostPart.getAmount returns 1
else if (costPart instanceof CostPartMana ) {
if (((CostPartMana) costPart).getManaToPay().isZero()) {
return GuiDialog.confirm(source, "Do you want to pay 0?" + orString);
}
}
//the following costs do not need inputs
for (CostPart part : parts) {

View File

@@ -86,6 +86,7 @@ public enum CSubmenuPreferences implements ICDoc {
lstControls.add(Pair.of(view.getCbOverlayCardManaCost(), FPref.UI_OVERLAY_CARD_MANA_COST));
lstControls.add(Pair.of(view.getCbShowMatchBackgroundImage(), FPref.UI_MATCH_IMAGE_VISIBLE));
lstControls.add(Pair.of(view.getCbUseThemedComboBox(), FPref.UI_THEMED_COMBOBOX));
lstControls.add(Pair.of(view.getCbPromptFreeBlocks(), FPref.MATCHPREF_PROMPT_FREE_BLOCKS));
for(final Pair<JCheckBox, FPref> kv : lstControls) {
kv.getKey().addItemListener(new ItemListener() {

View File

@@ -81,8 +81,9 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
private final JCheckBox cbOverlayCardPower = new OptionsCheckBox("Power/Toughness");
private final JCheckBox cbOverlayCardManaCost = new OptionsCheckBox("Mana Cost");
private final JCheckBox cbCompactMainMenu = new OptionsCheckBox("Use Compact Main Sidebar Menu");
private final JCheckBox cbShowMatchBackgroundImage = new OptionsCheckBox("Show Background Image on Match Screen");
private final JCheckBox cbShowMatchBackgroundImage = new OptionsCheckBox("Show Background Image on Match Screen");
private final JCheckBox cbUseThemedComboBox = new OptionsCheckBox("Themed ComboBox");
private final JCheckBox cbPromptFreeBlocks = new OptionsCheckBox("Free Block Handling");
private final Map<FPref, KeyboardShortcutField> shortcutFields = new HashMap<FPref, KeyboardShortcutField>();
@@ -146,7 +147,10 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
pnlPrefs.add(cbCloneImgSource, regularConstraints);
pnlPrefs.add(new NoteLabel("When enabled clones will use their original art instead of the cloned card's art"), regularConstraints);
pnlPrefs.add(cbPromptFreeBlocks, regularConstraints);
pnlPrefs.add(new NoteLabel("When enabled, if you would have to pay 0 to block, pay automatically without prompt"), regularConstraints);
// Deck building options
pnlPrefs.add(new SectionLabel("Random Deck Generation"), sectionConstraints);
@@ -489,6 +493,11 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
return cbCloneImgSource;
}
/** @return {@link javax.swing.JCheckBox} */
public JCheckBox getCbPromptFreeBlocks() {
return cbPromptFreeBlocks;
}
/** @return {@link javax.swing.JCheckBox} */
public JCheckBox getCbEnableSounds() {
return cbEnableSounds;

View File

@@ -64,6 +64,8 @@ public class ForgePreferences extends PreferencesStore<ForgePreferences.FPref> {
UI_FOR_TOUCHSCREN("false"),
MATCHPREF_PROMPT_FREE_BLOCKS("false"),
SUBMENU_CURRENTMENU (EMenuItem.CONSTRUCTED.toString()),
SUBMENU_SANCTIONED ("true"),
SUBMENU_GAUNTLET ("false"),