Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion forge-ai/src/main/java/forge/ai/ability/AttachAi.java
Original file line number Diff line number Diff line change
Expand Up @@ -1154,7 +1154,6 @@ private static Card attachAIPumpPreference(final Player ai, final SpellAbility s
totPower += AbilityUtils.calculateAmount(attachSource, stAbility.getParam("AddPower"), stAbility);

grantingAbilities |= stAbility.hasParam("AddAbility");
grantingExtraBlock |= stAbility.hasParam("CanBlockAmount") || stAbility.hasParam("CanBlockAny");

String kws = stAbility.getParam("AddKeyword");
if (kws != null) {
Expand Down
2 changes: 0 additions & 2 deletions forge-ai/src/main/java/forge/ai/ability/PumpAi.java
Original file line number Diff line number Diff line change
Expand Up @@ -330,8 +330,6 @@ protected AiAbilityDecision checkApiLogic(Player ai, SpellAbility sa) {
return new AiAbilityDecision(0, AiPlayDecision.DoesntImpactCombat);
}

return new AiAbilityDecision(100, AiPlayDecision.WillPlay);
} else if (grantsUsefulExtraBlockOpts(ai, sa, card, keywords)) {
return new AiAbilityDecision(100, AiPlayDecision.WillPlay);
}
}
Expand Down
43 changes: 0 additions & 43 deletions forge-ai/src/main/java/forge/ai/ability/PumpAiBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import forge.ai.*;
import forge.card.MagicColor;
import forge.game.Game;
import forge.game.ability.AbilityUtils;
import forge.game.card.*;
import forge.game.combat.Combat;
import forge.game.combat.CombatUtil;
Expand Down Expand Up @@ -31,48 +30,6 @@ public boolean containsUsefulKeyword(final Player ai, final List<String> keyword
return false;
}

public boolean grantsUsefulExtraBlockOpts(final Player ai, final SpellAbility sa, final Card card, List<String> keywords) {
PhaseHandler ph = ai.getGame().getPhaseHandler();
Card pumped = ComputerUtilCard.getPumpedCreature(ai, sa, card, 0, 0, keywords);

if (ph.isPlayerTurn(ai) || !ph.getPhase().equals(PhaseType.COMBAT_DECLARE_ATTACKERS)) {
return false;
}

int canBlockNum = 1 + card.canBlockAdditional();
int canBlockNumPumped = canBlockNum; // PumpedCreature doesn't return a meaningful value of canBlockAdditional, so we'll use sa params below

if (sa.hasParam("CanBlockAny")) {
canBlockNumPumped = Integer.MAX_VALUE;
} else if (sa.hasParam("CanBlockAmount")) {
canBlockNumPumped += AbilityUtils.calculateAmount(pumped, sa.getParam("CanBlockAmount"), sa);
}

int possibleBlockNum = 0;
int possibleBlockNumPumped = 0;

for (Card attacker : ai.getGame().getCombat().getAttackers()) {
if (CombatUtil.canBlock(attacker, card)) {
possibleBlockNum++;
if (possibleBlockNum > canBlockNum) {
possibleBlockNum = canBlockNum;
break;
}
}
}
for (Card attacker : ai.getGame().getCombat().getAttackers()) {
if (CombatUtil.canBlock(attacker, pumped)) {
possibleBlockNumPumped++;
if (possibleBlockNumPumped > canBlockNumPumped) {
possibleBlockNumPumped = canBlockNumPumped;
break;
}
}
}

return possibleBlockNumPumped > possibleBlockNum;
}

/**
* Checks if is useful keyword.
*
Expand Down
7 changes: 0 additions & 7 deletions forge-game/src/main/java/forge/game/StaticEffect.java
Original file line number Diff line number Diff line change
Expand Up @@ -307,13 +307,6 @@ final CardCollectionView remove(List<StaticAbilityLayer> layers) {
if (hasParam("Goad")) {
affectedCard.removeGoad(getTimestamp());
}

if (hasParam("CanBlockAny")) {
affectedCard.removeCanBlockAny(getTimestamp());
}
if (hasParam("CanBlockAmount")) {
affectedCard.removeCanBlockAdditional(getTimestamp());
}
}
}
return affectedCards;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,6 @@ private static void applyPump(final SpellAbility sa, final Card applyTo,
gameCard.updatePTforView();
}

if (sa.hasParam("CanBlockAny")) {
gameCard.addCanBlockAny(timestamp);
}
if (sa.hasParam("CanBlockAmount")) {
int v = AbilityUtils.calculateAmount(host, sa.getParam("CanBlockAmount"), sa, true);
gameCard.addCanBlockAdditional(v, timestamp);
}

if (sa.hasParam("LeaveBattlefield")) {
addLeaveBattlefieldReplacement(gameCard, sa, sa.getParam("LeaveBattlefield"));
}
Expand All @@ -103,17 +95,12 @@ public void run() {
host.removeGainControlTargets(gameCard);

gameCard.removePTBoost(timestamp, 0);
boolean updateText = gameCard.removeCanBlockAny(timestamp);
updateText |= gameCard.removeCanBlockAdditional(timestamp);

if (keywords.size() > 0) {
gameCard.removeHiddenExtrinsicKeywords(timestamp, 0);
gameCard.removeChangedCardKeywords(timestamp, 0);
}
gameCard.updatePTforView();
if (updateText) {
gameCard.updateAbilityTextForView();
}

game.fireEvent(new GameEventCardStatsChanged(gameCard));
}
Expand Down Expand Up @@ -238,21 +225,6 @@ protected String getStackDescription(final SpellAbility sa) {
sb.append(i+2 == keywords.size() ? "and " : "");
}

if (sa.hasParam("CanBlockAny")) {
if (gets || gains) {
sb.append(" and ");
}
sb.append("can block any number of creatures");
} else if (sa.hasParam("CanBlockAmount")) {
if (gets || gains) {
sb.append(" and ");
}
String n = sa.getParam("CanBlockAmount");
sb.append("can block an additional ");
sb.append("1".equals(n) ? "creature" : Lang.nounWithNumeral(n, "creature"));
sb.append(" each combat");
}

String duration = sa.getParam("Duration");
if (!"Permanent".equals(duration)) {
if ("UntilUntaps".equals(duration)) {
Expand Down
36 changes: 2 additions & 34 deletions forge-game/src/main/java/forge/game/card/Card.java
Original file line number Diff line number Diff line change
Expand Up @@ -175,9 +175,6 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr

private final Map<CounterType, StaticAbility> counterTypeKeywordStatic = Maps.newHashMap();

private final Map<Long, Integer> canBlockAdditional = Maps.newTreeMap();
private final Set<Long> canBlockAny = Sets.newHashSet();

// changes that say "replace each instance of one [color,type] by another - timestamp is the key of maps
private final CardChangedWords changedTextColors = new CardChangedWords();
private final CardChangedWords changedTextTypes = new CardChangedWords();
Expand Down Expand Up @@ -8129,41 +8126,12 @@ public void resetActivationsPerTurn() {
numberTurnActivations.clear();
}

public void addCanBlockAdditional(int n, long timestamp) {
if (n <= 0) {
return;
}
canBlockAdditional.put(timestamp, n);
getView().updateBlockAdditional(this);
}
public boolean removeCanBlockAdditional(long timestamp) {
boolean result = canBlockAdditional.remove(timestamp) != null;
if (result) {
getView().updateBlockAdditional(this);
}
return result;
}
public int canBlockAdditional() {
int result = 0;
for (Integer v : canBlockAdditional.values()) {
result += v;
}
return result;
return StaticAbilityCanBlockAmount.canBlockAmount(this);
}

public void addCanBlockAny(long timestamp) {
canBlockAny.add(timestamp);
getView().updateBlockAdditional(this);
}
public boolean removeCanBlockAny(long timestamp) {
boolean result = canBlockAny.remove(timestamp);
if (result) {
getView().updateBlockAdditional(this);
}
return result;
}
public boolean canBlockAny() {
return !canBlockAny.isEmpty();
return StaticAbilityCanBlockAmount.canBlockAny(this);
}

public boolean removeChangedState() {
Expand Down
28 changes: 0 additions & 28 deletions forge-game/src/main/java/forge/game/card/CardView.java
Original file line number Diff line number Diff line change
Expand Up @@ -917,21 +917,6 @@ public String getText(CardStateView state, HashMap<String, String> translationsT
sb.append("\r\n");
}

if (getCanBlockAny()) {
sb.append("\r\n\r\n");
sb.append("CARDNAME can block any number of creatures.".replaceAll("CARDNAME", getName()));
sb.append("\r\n");
} else {
int i = getBlockAdditional();
if (i > 0) {
sb.append("\r\n\r\n");
sb.append("CARDNAME can block an additional ".replaceAll("CARDNAME", getName()));
sb.append(i == 1 ? "creature" : Lang.nounWithNumeral(i, "creature"));
sb.append(" each combat.");
sb.append("\r\n");
}
}

Set<String> cantHaveKeyword = this.getCantHaveKeyword();
if (cantHaveKeyword != null && !cantHaveKeyword.isEmpty()) {
sb.append("\r\n\r\n");
Expand Down Expand Up @@ -1168,19 +1153,6 @@ void updateHiddenId(final int hiddenId) {
set(TrackableProperty.HiddenId, hiddenId);
}

int getBlockAdditional() {
return get(TrackableProperty.BlockAdditional);
}

boolean getCanBlockAny() {
return get(TrackableProperty.BlockAny);
}

void updateBlockAdditional(Card c) {
set(TrackableProperty.BlockAdditional, c.canBlockAdditional());
set(TrackableProperty.BlockAny, c.canBlockAny());
}

public boolean isRingBearer() {
return get(TrackableProperty.IsRingBearer);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ private Set<StaticAbilityLayer> generateLayer() {
}

if (hasParam("AddHiddenKeyword") || hasParam("MayPlay")
|| hasParam("IgnoreEffectCost") || hasParam("Goad") || hasParam("CanBlockAny") || hasParam("CanBlockAmount")
|| hasParam("IgnoreEffectCost") || hasParam("Goad")
|| hasParam("AdjustLandPlays") || hasParam("ControlVote") || hasParam("AdditionalVote") || hasParam("AdditionalOptionalVote")
|| hasParam("DeclaresAttackers") || hasParam("DeclaresBlockers")) {
layers.add(StaticAbilityLayer.RULES);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package forge.game.staticability;

import forge.game.Game;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
import forge.game.zone.ZoneType;

public class StaticAbilityCanBlockAmount {
static public boolean canBlockAny(final Card blocker) {
final Game game = blocker.getGame();

for (final Card ca : game.getCardsIn(ZoneType.STATIC_ABILITIES_SOURCE_ZONES)) {
for (final StaticAbility stAb : ca.getStaticAbilities()) {
if (!stAb.checkConditions(StaticAbilityMode.CanBlockAmount)) {
continue;
}
if (isValid(stAb, blocker) && "Any".equals(stAb.getParam("Amount"))) {
return true;
}
}
}
return false;
}

static public int canBlockAmount(final Card blocker) {
final Game game = blocker.getGame();

int i = 0;
for (final Card ca : game.getCardsIn(ZoneType.STATIC_ABILITIES_SOURCE_ZONES)) {
for (final StaticAbility stAb : ca.getStaticAbilities()) {
if (!stAb.checkConditions(StaticAbilityMode.CanBlockAmount)) {
continue;
}
if (isValid(stAb, blocker) && !"Any".equals(stAb.getParam("Amount"))) {
i += AbilityUtils.calculateAmount(stAb.getHostCard(), stAb.getParamOrDefault("Amount", "1"), stAb);
}
}
}
return i;

}

static public boolean isValid(StaticAbility stAb, Card blocker) {
if (!stAb.matchesValidParam("ValidCard", blocker)) {
return false;
}
return true;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -875,13 +875,6 @@ public static CardCollectionView applyContinuousAbility(final StaticAbility stAb
if (params.containsKey("Goad")) {
affectedCard.addGoad(se.getTimestamp(), hostCard.getController());
}
if (params.containsKey("CanBlockAny")) {
affectedCard.addCanBlockAny(se.getTimestamp());
}
if (params.containsKey("CanBlockAmount")) {
int v = AbilityUtils.calculateAmount(hostCard, params.get("CanBlockAmount"), stAb, true);
affectedCard.addCanBlockAdditional(v, se.getTimestamp());
}
}

if (controllerMayPlay && (mayPlayLimit == null || stAb.getMayPlayTurn() < mayPlayLimit)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ public enum StaticAbilityMode {
// StaticAbilityMustTarget
MustTarget,

// StaticAbilityCanBlockAmount
CanBlockAmount,

// StaticAbilityCantAttackBlock
CantAttack,
CanAttackDefender,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,8 +187,6 @@ public enum TrackableProperty {
HasStorm(TrackableTypes.BooleanType),
HasWard(TrackableTypes.BooleanType),
HasWither(TrackableTypes.BooleanType),
BlockAdditional(TrackableTypes.IntegerType),
BlockAny(TrackableTypes.BooleanType),
AbilityText(TrackableTypes.StringType),
NonAbilityText(TrackableTypes.StringType),
FoilIndex(TrackableTypes.IntegerType),
Expand Down
4 changes: 3 additions & 1 deletion forge-gui/res/cardsfolder/a/act_of_heroism.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,7 @@ Name:Act of Heroism
ManaCost:1 W
Types:Instant
A:SP$ Untap | ValidTgts$ Creature | SubAbility$ DBPump | SpellDescription$ Untap target creature. It gets +2/+2 until end of turn and can block an additional creature this turn.
SVar:DBPump:DB$ Pump | Defined$ Targeted | NumAtt$ +2 | NumDef$ +2 | CanBlockAmount$ 1
SVar:DBPump:DB$ Pump | Defined$ Targeted | NumAtt$ +2 | NumDef$ +2 | SubAbility$ DBEffect
SVar:DBEffect:DB$ Effect | ValidTgts$ Creature | RememberObjects$ Targeted | ExileOnMoved$ Battlefield | StaticAbilities$ DBBlock | AILogic$ Pump | StackDescription$ {c:Targeted} can block any number of creatures this turn. | SpellDescription$ Target creature can block any number of creatures this turn.
SVar:DBBlock:Mode$ CanBlockAmount | ValidCard$ Card.IsRemembered | Amount$ 1 | Description$ Creature can block an additional creature this turn.
Oracle:Untap target creature. It gets +2/+2 until end of turn and can block an additional creature this turn.
3 changes: 2 additions & 1 deletion forge-gui/res/cardsfolder/a/anurid_swarmsnapper.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ ManaCost:2 G
Types:Creature Frog Beast
PT:1/4
K:Reach
A:AB$ Pump | Cost$ 1 G | Defined$ Self | CanBlockAmount$ 1 | SpellDescription$ CARDNAME can block an additional creature this turn.
A:AB$ Effect | Cost$ 1 G | Duration$ UntilHostLeavesPlayOrEOT | StaticAbilities$ DBBlock | AILogic$ Pump | StackDescription$ SpellDescription | SpellDescription$ CARDNAME can block an additional creature this turn.
SVar:DBBlock:Mode$ CanBlockAmount | ValidCard$ Card.EffectSource | Amount$ 1 | Description$ EFFECTSOURCE can block an additional creature this turn.
Oracle:Reach (This creature can block creatures with flying.)\n{1}{G}: Anurid Swarmsnapper can block an additional creature this turn.
2 changes: 1 addition & 1 deletion forge-gui/res/cardsfolder/a/avatar_of_hope.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ Types:Creature Avatar
PT:4/9
S:Mode$ ReduceCost | ValidCard$ Card.Self | Type$ Spell | Amount$ 6 | EffectZone$ All | CheckSVar$ NeedHope | SVarCompare$ LE3 | Description$ If you have 3 or less life, CARDNAME costs {6} less to cast.
K:Flying
S:Mode$ Continuous | Affected$ Card.Self | CanBlockAny$ True | Description$ CARDNAME can block any number of creatures.
S:Mode$ CanBlockAmount | ValidCard$ Card.Self | Amount$ Any | Description$ CARDNAME can block any number of creatures.
SVar:NeedHope:Count$YourLifeTotal
Oracle:If you have 3 or less life, this spell costs {6} less to cast.\nFlying\nAvatar of Hope can block any number of creatures.
3 changes: 2 additions & 1 deletion forge-gui/res/cardsfolder/b/blaze_of_glory.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
Name:Blaze of Glory
ManaCost:W
Types:Instant
A:SP$ Pump | ValidTgts$ Creature.DefendingPlayerCtrl | TgtPrompt$ Select target creature defending player controls | CanBlockAny$ True | SubAbility$ GoingDownInStyle | ActivationPhases$ BeginCombat->Declare Attackers | StackDescription$ {c:Targeted} can block any number of creatures this turn. It blocks each attacking creature this turn if able. | SpellDescription$ Cast CARDNAME only during combat before blockers are declared. Target creature defending player controls can block any number of creatures this turn. It blocks each attacking creature this turn if able.
A:SP$ Effect | ValidTgts$ Creature.DefendingPlayerCtrl | TgtPrompt$ Select target creature defending player controls | RememberObjects$ Targeted | ExileOnMoved$ Battlefield | StaticAbilities$ DBBlock | AILogic$ Pump | SubAbility$ GoingDownInStyle | ActivationPhases$ BeginCombat->Declare Attackers | StackDescription$ {c:Targeted} can block any number of creatures this turn. It blocks each attacking creature this turn if able. | SpellDescription$ Cast CARDNAME only during combat before blockers are declared. Target creature defending player controls can block any number of creatures this turn. It blocks each attacking creature this turn if able.
SVar:DBBlock:Mode$ CanBlockAmount | ValidCard$ Card.IsRemembered | Amount$ Any | Description$ This creature can block any number of creatures.
SVar:GoingDownInStyle:DB$ MustBlock | Defined$ ParentTarget | DefinedAttacker$ Valid Card.attacking | BlockAllDefined$ True | StackDescription$ None
AI:RemoveDeck:All
Oracle:Cast this spell only during combat before blockers are declared.\nTarget creature defending player controls can block any number of creatures this turn. It blocks each attacking creature this turn if able.
2 changes: 1 addition & 1 deletion forge-gui/res/cardsfolder/b/brave_the_sands.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Name:Brave the Sands
ManaCost:1 W
Types:Enchantment
S:Mode$ Continuous | Affected$ Creature.YouCtrl | AddKeyword$ Vigilance | Description$ Creatures you control have vigilance.
S:Mode$ Continuous | Affected$ Creature.YouCtrl | CanBlockAmount$ 1 | Description$ Each creature you control can block an additional creature each combat.
S:Mode$ CanBlockAmount | ValidCard$ Creature.Self | Amount$ 1 | Description$ Each creature you control can block an additional creature each combat.
SVar:NonStackingEffect:True
SVar:PlayMain1:TRUE
Oracle:Creatures you control have vigilance.\nEach creature you control can block an additional creature each combat.
2 changes: 1 addition & 1 deletion forge-gui/res/cardsfolder/c/cenns_tactician.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ ManaCost:W
Types:Creature Kithkin Soldier
PT:1/1
A:AB$ PutCounter | Cost$ W T | ValidTgts$ Creature.Soldier | TgtPrompt$ Select target soldier creature | CounterType$ P1P1 | CounterNum$ 1 | SpellDescription$ Put a +1/+1 counter on target Soldier creature.
S:Mode$ Continuous | Affected$ Creature.YouCtrl+counters_GE1_P1P1 | CanBlockAmount$ 1 | Description$ Each creature you control with a +1/+1 counter on it can block an additional creature each combat.
S:Mode$ CanBlockAmount | ValidCard$ Creature.YouCtrl+counters_GE1_P1P1 | Amount$ 1 | Description$ Each creature you control with a +1/+1 counter on it can block an additional creature each combat.
Oracle:{W}, {T}: Put a +1/+1 counter on target Soldier creature.\nEach creature you control with a +1/+1 counter on it can block an additional creature each combat.
3 changes: 2 additions & 1 deletion forge-gui/res/cardsfolder/c/coastline_chimera.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ ManaCost:3 U
Types:Creature Chimera
PT:1/5
K:Flying
A:AB$ Pump | Cost$ 1 W | Defined$ Self | CanBlockAmount$ 1 | SpellDescription$ CARDNAME can block an additional creature this turn.
A:AB$ Effect | Cost$ 1 W | Duration$ UntilHostLeavesPlayOrEOT | StaticAbilities$ DBBlock | AILogic$ Pump | StackDescription$ SpellDescription | SpellDescription$ CARDNAME can block an additional creature this turn.
SVar:DBBlock:Mode$ CanBlockAmount | ValidCard$ Card.EffectSource | Amount$ 1 | Description$ EFFECTSOURCE can block an additional creature this turn.
Oracle:Flying\n{1}{W}: Coastline Chimera can block an additional creature this turn.
2 changes: 1 addition & 1 deletion forge-gui/res/cardsfolder/e/echo_circlet.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ Name:Echo Circlet
ManaCost:2
Types:Artifact Equipment
K:Equip:1
S:Mode$ Continuous | Affected$ Creature.EquippedBy | CanBlockAmount$ 1 | Description$ Equipped creature can block an additional creature each combat.
S:Mode$ CanBlockAmount | ValidCard$ Creature.EquippedBy | Amount$ 1 | Description$ Equipped creature can block an additional creature each combat.
Oracle:Equipped creature can block an additional creature each combat.\nEquip {1}
Loading