mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-20 20:58:03 +00:00
- Added the new static ability CantAttackUnless.
This commit is contained in:
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user