- Added the new static ability CantAttackUnless.

This commit is contained in:
Sloth
2012-09-26 18:28:57 +00:00
parent eb8ca4bd29
commit d94843e38c
15 changed files with 230 additions and 121 deletions

1
.gitattributes vendored
View File

@@ -12177,6 +12177,7 @@ src/main/java/forge/card/spellability/TargetChoices.java svneol=native#text/plai
src/main/java/forge/card/spellability/TargetSelection.java svneol=native#text/plain
src/main/java/forge/card/spellability/package-info.java svneol=native#text/plain
src/main/java/forge/card/staticability/StaticAbility.java svneol=native#text/plain
src/main/java/forge/card/staticability/StaticAbilityCantAttackBlock.java -text
src/main/java/forge/card/staticability/StaticAbilityCantBeCast.java svneol=native#text/plain
src/main/java/forge/card/staticability/StaticAbilityCantTarget.java -text
src/main/java/forge/card/staticability/StaticAbilityContinuous.java svneol=native#text/plain

View File

@@ -4,7 +4,7 @@ Types:Enchantment Aura
Text:no text
K:Enchant creature
A:SP$ Attach | Cost$ W | ValidTgts$ Creature | AILogic$ Curse
K:Creatures can't attack unless their controller pays:Creature.AttachedBy:3:Enchanted creature can't attack unless its controller pays 3.
S:Mode$ CantAttackUnless | ValidCard$ Creature.AttachedBy | Cost$ 3 | Description$ Enchanted creature can't attack unless its controller pays 3.
SVar:Rarity:Common
SVar:Picture:http://www.wizards.com/global/images/magic/general/brainwash.jpg
SetInfo:5ED|Common|http://magiccards.info/scans/en/5e/289.jpg

View File

@@ -2,7 +2,7 @@ Name:Collective Restraint
ManaCost:3 U
Types:Enchantment
Text:no text
K:Creatures can't attack unless their controller pays:Creature.YouDontCtrl:X:Domain - Creatures can't attack you unless their controller pays X for each creature he or she controls that's attacking you, where X is the number of basic land types among lands you control.
S:Mode$ CantAttackUnless | ValidCard$ Creature | Target$ You | Cost$ X | Description$ Domain - Creatures can't attack you unless their controller pays X for each creature he or she controls that's attacking you, where X is the number of basic land types among lands you control.
SVar:X:Count$Domain
SVar:Rarity:Rare
SVar:Picture:http://www.wizards.com/global/images/magic/general/collective_restraint.jpg

View File

@@ -4,7 +4,7 @@ Types:Enchantment
Text:no text
K:Cumulative upkeep:1
S:Mode$ Continuous | Affected$ Creature.Black+YouDontCtrl | AddHiddenKeyword$ HIDDEN CARDNAME can't attack. | Description$ Black creatures can't attack you.
K:Creatures can't attack unless their controller pays:Creature.nonBlack+YouDontCtrl:2:Nonblack creatures can't attack you unless their controller pays 2 for each creature he or she controls that's attacking you.
S:Mode$ CantAttackUnless | ValidCard$ Creature.nonBlack | Target$ You | Cost$ 2 | Description$ Nonblack creatures can't attack you unless their controller pays 2 for each creature he or she controls that's attacking you.
SVar:Rarity:Uncommon
SVar:Picture:http://www.wizards.com/global/images/magic/general/elephant_grass.jpg
SetInfo:VIS|Uncommon|http://magiccards.info/scans/en/vi/54.jpg

View File

@@ -2,7 +2,7 @@ Name:Ghostly Prison
ManaCost:2 W
Types:Enchantment
Text:no text
K:Creatures can't attack unless their controller pays:Creature.YouDontCtrl:2:Creatures can't attack you unless their controller pays 2 for each creature he or she controls that's attacking you.
S:Mode$ CantAttackUnless | ValidCard$ Creature | Target$ You | Cost$ 2 | Description$ Creatures can't attack you unless their controller pays 2 for each creature he or she controls that's attacking you.
SVar:Rarity:Uncommon
SVar:Picture:http://www.wizards.com/global/images/magic/general/ghostly_prison.jpg
SetInfo:CHK|Uncommon|http://magiccards.info/scans/en/chk/10.jpg

View File

@@ -4,7 +4,7 @@ Types:Artifact Creature Construct
Text:no text
PT:0/0
K:CARDNAME can't block.
K:Creatures can't attack unless their controller pays:Card.Self:Y:CARDNAME can't attack unless you pay 1 for each +1/+1 counter on it.
S:Mode$ CantAttackUnless | ValidCard$ Card.Self | Cost$ Y | Description$ CARDNAME can't attack unless you pay 1 for each +1/+1 counter on it.
K:etbCounter:P1P1:X
SVar:X:Count$xPaid
SVar:Y:Count$NumCounters.P1P1

View File

@@ -2,7 +2,7 @@ Name:Propaganda
ManaCost:2 U
Types:Enchantment
Text:no text
K:Creatures can't attack unless their controller pays:Creature.YouDontCtrl:2:Creatures can't attack you unless their controller pays 2 for each creature he or she controls that's attacking you.
S:Mode$ CantAttackUnless | ValidCard$ Creature | Target$ You | Cost$ 2 | Description$ Creatures can't attack you unless their controller pays 2 for each creature he or she controls that's attacking you.
SVar:Rarity:Uncommon
SVar:Picture:http://www.wizards.com/global/images/magic/general/propaganda.jpg
SetInfo:TMP|Uncommon|http://magiccards.info/scans/en/tp/80.jpg

View File

@@ -2,7 +2,7 @@ Name:Windborn Muse
ManaCost:3 W
Types:Creature Spirit
Text:no text
K:Creatures can't attack unless their controller pays:Creature.YouDontCtrl:2:Creatures can't attack you unless their controller pays 2 for each creature he or she controls that's attacking you.
S:Mode$ CantAttackUnless | ValidCard$ Creature | Target$ You | Cost$ 2 | Description$ Creatures can't attack you unless their controller pays 2 for each creature he or she controls that's attacking you.
PT:2/3
K:Flying
SVar:Rarity:Rare

View File

@@ -34,7 +34,7 @@ import forge.card.cost.CostMana;
import forge.card.cost.CostPutCounter;
import forge.card.cost.CostReturn;
import forge.card.cost.CostSacrifice;
import forge.card.mana.ManaCost;
import forge.card.cost.CostUtil;
import forge.card.spellability.Ability;
import forge.card.spellability.AbilityMana;
import forge.card.spellability.AbilitySub;
@@ -447,7 +447,8 @@ public final class GameActionUtil {
* a {@link forge.Command} object.
* @param sourceAbility TODO
*/
public static void payCostDuringAbilityResolve(final SpellAbility ability, final Cost cost, final Command paid, final Command unpaid, SpellAbility sourceAbility) {
public static void payCostDuringAbilityResolve(final SpellAbility ability, final Cost cost, final Command paid,
final Command unpaid, SpellAbility sourceAbility) {
final Card source = ability.getSourceCard();
final ArrayList<CostPart> parts = cost.getCostParts();
if (parts.size() > 1) {
@@ -1687,24 +1688,7 @@ public final class GameActionUtil {
public static Cost combineCosts(SpellAbility sa, String additionalCost) {
final Cost newCost = new Cost(sa.getSourceCard(), additionalCost, false);
Cost oldCost = sa.getPayCosts();
if (sa.getPayCosts() != null) {
for (final CostPart part : oldCost.getCostParts()) {
if (!(part instanceof CostMana)) {
newCost.getCostParts().add(part);
} else {
CostMana newCostMana = newCost.getCostMana();
if (newCostMana != null) {
ManaCost oldManaCost = new ManaCost(part.toString());
newCostMana.setXMana(oldManaCost.getXcounter() + newCostMana.getXMana());
oldManaCost.combineManaCost(newCostMana.toString());
newCostMana.setMana(oldManaCost.toString(false));
} else {
newCost.getCostParts().add(part);
}
}
}
}
return newCost;
return CostUtil.combineCosts(oldCost, newCost);
}
/**

View File

@@ -3433,48 +3433,6 @@ public class CardFactoryUtil {
return maxColor;
}
/**
* <p>
* Get the total cost to pay for an attacker c, due to cards like
* Propaganda, Ghostly Prison, Collective Restraint, ...
* </p>
*
* @param c
* a {@link forge.Card} object.
* @return a {@link java.lang.String} object.
*/
public static String getPropagandaCost(final Card c) {
int cost = 0;
final CardList list = AllZoneUtil.getCardsIn(ZoneType.Battlefield);
for (final Card card : list) {
if (card.hasStartOfKeyword("Creatures can't attack unless their controller pays")) {
final int keywordPosition = card
.getKeywordPosition("Creatures can't attack unless their controller pays");
final String parse = card.getKeyword().get(keywordPosition).toString();
final String[] k = parse.split(":");
final String[] restrictions = k[1].split(",");
if (!c.isValid(restrictions, card.getController(), card)) {
continue;
}
final String costString = k[2];
if (costString.equals("X")) {
cost += CardFactoryUtil.xCount(card, card.getSVar("X"));
} else if (costString.equals("Y")) {
cost += CardFactoryUtil.xCount(card, card.getSVar("Y"));
} else {
cost += Integer.parseInt(k[2]);
}
}
}
final String s = Integer.toString(cost);
return s;
}
/**
* <p>
* getUsableManaSources.

View File

@@ -184,7 +184,11 @@ public class Cost {
public Cost(final Card card, String parse, final boolean bAbility) {
this.isAbility = bAbility;
// when adding new costs for cost string, place them here
this.name = card.getName();
String name = "";
if (card != null) {
name = card.getName();
}
this.name = name;
while (parse.contains(Cost.TAP_X_STR)) {
final String[] splitStr = this.abCostParse(parse, Cost.TAP_X_STR, 3);

View File

@@ -24,6 +24,7 @@ import forge.Card;
import forge.CardList;
import forge.Counters;
import forge.card.abilityfactory.AbilityFactory;
import forge.card.mana.ManaCost;
import forge.card.spellability.SpellAbility;
import forge.control.input.Input;
import forge.game.player.ComputerUtil;
@@ -456,4 +457,36 @@ public class CostUtil {
// Just a shortcut..
AllZone.getInputControl().setInput(in, true);
}
public static Cost combineCosts(Cost cost1, Cost cost2) {
if (cost1 == null) {
if (cost2 == null) {
return null;
} else {
return cost2;
}
}
if (cost2 == null) {
return cost1;
}
for (final CostPart part : cost1.getCostParts()) {
if (!(part instanceof CostMana)) {
cost2.getCostParts().add(part);
} else {
CostMana newCostMana = cost2.getCostMana();
if (newCostMana != null) {
ManaCost oldManaCost = new ManaCost(part.toString());
newCostMana.setXMana(oldManaCost.getXcounter() + newCostMana.getXMana());
oldManaCost.combineManaCost(newCostMana.toString());
newCostMana.setMana(oldManaCost.toString(false));
} else {
cost2.getCostParts().add(part);
}
}
}
return cost2;
}
}

View File

@@ -27,6 +27,7 @@ import forge.Card;
import forge.GameEntity;
import forge.Singletons;
import forge.card.abilityfactory.AbilityFactory;
import forge.card.cost.Cost;
import forge.card.mana.ManaCost;
import forge.card.spellability.SpellAbility;
import forge.game.phase.PhaseType;
@@ -408,6 +409,39 @@ public class StaticAbility {
return false;
}
/**
* Apply ability.
*
* @param mode
* the mode
* @param card
* the card
* @param target
* the target
* @return true, if successful
*/
public final Cost getCostAbility(final String mode, final Card card, final GameEntity target) {
// don't apply the ability if it hasn't got the right mode
if (!this.mapParams.get("Mode").equals(mode)) {
return null;
}
if (this.isSuppressed() || !this.checkConditions()) {
return null;
}
if (mode.equals("CantAttackUnless")) {
return StaticAbilityCantAttackBlock.applyCantAttackUnlessAbility(this, card, target);
}
if (mode.equals("CantBlockUnless")) {
return StaticAbilityCantAttackBlock.applyCantBlockUnlessAbility(this, card);
}
return null;
}
/**
* Check conditions.
*

View File

@@ -0,0 +1,89 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.card.staticability;
import java.util.HashMap;
import forge.Card;
import forge.GameEntity;
import forge.card.cardfactory.CardFactoryUtil;
import forge.card.cost.Cost;
/**
* The Class StaticAbility_CantBeCast.
*/
public class StaticAbilityCantAttackBlock{
/**
* TODO Write javadoc for this method.
*
* @param stAb
* a StaticAbility
* @param card
* the card
* @return a Cost
*/
public static Cost applyCantAttackUnlessAbility(final StaticAbility stAb, final Card card, final GameEntity target) {
final HashMap<String, String> params = stAb.getMapParams();
final Card hostCard = stAb.getHostCard();
if (params.containsKey("ValidCard")
&& !card.isValid(params.get("ValidCard").split(","), hostCard.getController(), hostCard)) {
return null;
}
if (params.containsKey("Target")
&& !target.isValid(params.get("Target").split(","), hostCard.getController(), hostCard)) {
return null;
}
String costString = params.get("Cost");
if ("X".equals(costString)) {
costString = Integer.toString(CardFactoryUtil.xCount(hostCard, hostCard.getSVar("X")));
} else if ("Y".equals(costString)) {
costString = Integer.toString(CardFactoryUtil.xCount(hostCard, hostCard.getSVar("Y")));
}
final Cost cost = new Cost(hostCard, costString, true);
return cost;
}
/**
* TODO Write javadoc for this method.
*
* @param stAb
* a StaticAbility
* @param card
* the card
* @return a Cost
*/
public static Cost applyCantBlockUnlessAbility(final StaticAbility stAb, final Card card) {
final HashMap<String, String> params = stAb.getMapParams();
final Card hostCard = stAb.getHostCard();
if (params.containsKey("ValidCard")
&& !card.isValid(params.get("ValidCard").split(","), hostCard.getController(), hostCard)) {
return null;
}
final Cost cost = new Cost(hostCard, params.get("Cost"), true);
return cost;
}
}

View File

@@ -43,14 +43,16 @@ import forge.card.TriggerReplacementBase;
import forge.card.abilityfactory.AbilityFactory;
import forge.card.abilityfactory.AbilityFactorySacrifice;
import forge.card.cardfactory.CardFactoryUtil;
import forge.card.cost.Cost;
import forge.card.cost.CostUtil;
import forge.card.spellability.Ability;
import forge.card.spellability.AbilityActivated;
import forge.card.spellability.AbilityStatic;
import forge.card.spellability.SpellAbility;
import forge.card.staticability.StaticAbility;
import forge.card.trigger.Trigger;
import forge.card.trigger.TriggerHandler;
import forge.card.trigger.TriggerType;
import forge.control.input.InputPayManaCostAbility;
import forge.game.player.ComputerUtil;
import forge.game.player.ComputerUtilBlock;
import forge.game.player.Player;
@@ -2650,8 +2652,16 @@ public class CombatUtil {
* a boolean.
*/
public static void checkPropagandaEffects(final Card c, final boolean bLast) {
final String cost = CardFactoryUtil.getPropagandaCost(c);
if (cost.equals("0")) {
Cost attackCost = new Cost(c, "0", true);
// Sort abilities to apply them in proper order
for (Card card : AllZoneUtil.getCardsIn(ZoneType.Battlefield)) {
final ArrayList<StaticAbility> staticAbilities = card.getStaticAbilities();
for (final StaticAbility stAb : staticAbilities) {
Cost additionalCost = stAb.getCostAbility("CantAttackUnless", c, AllZone.getCombat().getDefenderByAttacker(c));
attackCost = CostUtil.combineCosts(attackCost, additionalCost);
}
}
if (attackCost.toSimpleString().equals("")) {
if (!c.hasKeyword("Vigilance")) {
c.tap();
}
@@ -2667,8 +2677,7 @@ public class CombatUtil {
final PhaseType phase = Singletons.getModel().getGameState().getPhaseHandler().getPhase();
if (phase == PhaseType.COMBAT_DECLARE_ATTACKERS || phase == PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY) {
if (!cost.equals("0")) {
final Ability ability = new Ability(c, cost) {
final Ability ability = new AbilityStatic(c, attackCost, null) {
@Override
public void resolve() {
@@ -2706,9 +2715,7 @@ public class CombatUtil {
};
if (c.getController().isHuman()) {
AllZone.getInputControl().setInput(
new InputPayManaCostAbility(c + " - Pay to Attack\r\n", ability.getManaCost(), paidCommand,
unpaidCommand));
GameActionUtil.payCostDuringAbilityResolve(ability, attackCost, paidCommand, unpaidCommand, null);
} else { // computer
if (ComputerUtil.canPayCost(ability)) {
ComputerUtil.playNoStack(ability);
@@ -2726,7 +2733,6 @@ public class CombatUtil {
}
}
}
}
/**
* <p>