mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-15 10:18:01 +00:00
BlockEffect and related cards
This commit is contained in:
@@ -27,6 +27,7 @@ public enum ApiType {
|
||||
BecomeMonarch (BecomeMonarchEffect.class),
|
||||
BecomesBlocked (BecomesBlockedEffect.class),
|
||||
BidLife (BidLifeEffect.class),
|
||||
Block (BlockEffect.class),
|
||||
Bond (BondEffect.class),
|
||||
Branch (BranchEffect.class),
|
||||
ChangeCombatants (ChangeCombatantsEffect.class),
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
package forge.game.ability.effects;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.SpellAbilityEffect;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardCollection;
|
||||
import forge.game.combat.Combat;
|
||||
import forge.game.event.GameEventCombatChanged;
|
||||
import forge.game.Game;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.trigger.TriggerType;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class BlockEffect extends SpellAbilityEffect {
|
||||
|
||||
@Override
|
||||
public void resolve(SpellAbility sa) {
|
||||
final Card host = sa.getHostCard();
|
||||
final Game game = host.getGame();
|
||||
final Combat combat = game.getPhaseHandler().getCombat();
|
||||
|
||||
List<Card> attackers = new ArrayList<Card>();
|
||||
if (sa.hasParam("DefinedAttacker")) {
|
||||
for (final Card attacker : AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam("DefinedAttacker"), sa)) {
|
||||
if (combat.isAttacking(attacker)) attackers.add(attacker);
|
||||
}
|
||||
}
|
||||
|
||||
List<Card> blockers = new ArrayList<Card>();
|
||||
if (sa.hasParam("DefinedBlocker")) {
|
||||
for (final Card blocker : AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam("DefinedBlocker"), sa)) {
|
||||
if (blocker.isCreature()) blockers.add(blocker);
|
||||
}
|
||||
}
|
||||
|
||||
if (attackers.size() == 0 || blockers.size() == 0) return;
|
||||
|
||||
for (final Card attacker : attackers) {
|
||||
final boolean wasBlocked = combat.isBlocked(attacker);
|
||||
|
||||
for (final Card blocker : blockers) {
|
||||
// If the attacker was blocked, this covers adding the blocker to the damage assignment
|
||||
combat.addBlocker(attacker, blocker);
|
||||
combat.orderAttackersForDamageAssignment(blocker);
|
||||
|
||||
blocker.addBlockedThisTurn(attacker);
|
||||
attacker.addBlockedByThisTurn(blocker);
|
||||
|
||||
Map<String, Object> runParams = Maps.newHashMap();
|
||||
runParams.put("Attacker", attacker);
|
||||
runParams.put("Blocker", blocker);
|
||||
game.getTriggerHandler().runTrigger(TriggerType.AttackerBlockedByCreature, runParams, false);
|
||||
|
||||
runParams = Maps.newHashMap();
|
||||
runParams.put("Blocker", blocker);
|
||||
runParams.put("Attackers", attacker);
|
||||
game.getTriggerHandler().runTrigger(TriggerType.Blocks, runParams, false);
|
||||
}
|
||||
|
||||
attacker.getDamageHistory().setCreatureGotBlockedThisCombat(true);
|
||||
if (!wasBlocked) {
|
||||
final Map<String, Object> runParams = Maps.newHashMap();
|
||||
runParams.put("Attacker", attacker);
|
||||
runParams.put("Blockers", blockers);
|
||||
runParams.put("NumBlockers", blockers.size());
|
||||
runParams.put("Defender", combat.getDefenderByAttacker(attacker));
|
||||
runParams.put("DefendingPlayer", combat.getDefenderPlayerByAttacker(attacker));
|
||||
game.getTriggerHandler().runTrigger(TriggerType.AttackerBlocked, runParams, false);
|
||||
|
||||
combat.orderBlockersForDamageAssignment(attacker, new CardCollection(blockers));
|
||||
}
|
||||
}
|
||||
|
||||
game.updateCombatForView();
|
||||
game.fireEvent(new GameEventCombatChanged());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getStackDescription(SpellAbility sa) {
|
||||
final Card host = sa.getHostCard();
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
|
||||
// end standard pre-
|
||||
|
||||
List<String> attackers = new ArrayList<String>();
|
||||
if (sa.hasParam("DefinedAttacker")) {
|
||||
for (final Card attacker : AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam("DefinedAttacker"), sa)) {
|
||||
attackers.add(attacker.toString());
|
||||
}
|
||||
}
|
||||
|
||||
List<String> blockers = new ArrayList<String>();
|
||||
if (sa.hasParam("DefinedBlocker")) {
|
||||
for (final Card blocker : AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam("DefinedBlocker"), sa)) {
|
||||
blockers.add(blocker.toString());
|
||||
}
|
||||
}
|
||||
|
||||
sb.append(String.join(", ", blockers)).append(" block ").append(String.join(", ", attackers));
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -449,7 +449,7 @@ public class Combat {
|
||||
|
||||
for (Card attacker : band.getAttackers()) {
|
||||
if (blockers.size() <= 1) {
|
||||
blockersOrderedForDamageAssignment.put(attacker, new CardCollection(blockers));
|
||||
orderBlockersForDamageAssignment(attacker, new CardCollection(blockers));
|
||||
}
|
||||
else { // process it a bit later
|
||||
blockersNeedManualOrdering.add(Pair.of(attacker, new CardCollection(blockers))); // we know there's a list
|
||||
@@ -459,27 +459,37 @@ public class Combat {
|
||||
|
||||
// brought this out of iteration on bands to avoid concurrency problems
|
||||
for (Pair<Card, CardCollection> pair : blockersNeedManualOrdering) {
|
||||
// Damage Ordering needs to take cards like Melee into account, is that happening?
|
||||
CardCollection orderedBlockers = playerWhoAttacks.getController().orderBlockers(pair.getLeft(), pair.getRight()); // we know there's a list
|
||||
blockersOrderedForDamageAssignment.put(pair.getLeft(), orderedBlockers);
|
||||
|
||||
// Display the chosen order of blockers in the log
|
||||
// TODO: this is best done via a combat panel update
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(playerWhoAttacks.getName());
|
||||
sb.append(" has ordered blockers for ");
|
||||
sb.append(pair.getLeft());
|
||||
sb.append(": ");
|
||||
for (int i = 0; i < orderedBlockers.size(); i++) {
|
||||
sb.append(orderedBlockers.get(i));
|
||||
if (i != orderedBlockers.size() - 1) {
|
||||
sb.append(", ");
|
||||
}
|
||||
}
|
||||
playerWhoAttacks.getGame().getGameLog().add(GameLogEntryType.COMBAT, sb.toString());
|
||||
orderBlockersForDamageAssignment(pair.getLeft(), pair.getRight());
|
||||
}
|
||||
}
|
||||
|
||||
/** If there are multiple blockers, the Attacker declares the Assignment Order */
|
||||
public void orderBlockersForDamageAssignment(Card attacker, CardCollection blockers) { // this method performs controller's role
|
||||
if (blockers.size() <= 1) {
|
||||
blockersOrderedForDamageAssignment.put(attacker, new CardCollection(blockers));
|
||||
return;
|
||||
}
|
||||
|
||||
// Damage Ordering needs to take cards like Melee into account, is that happening?
|
||||
CardCollection orderedBlockers = playerWhoAttacks.getController().orderBlockers(attacker, blockers); // we know there's a list
|
||||
blockersOrderedForDamageAssignment.put(attacker, orderedBlockers);
|
||||
|
||||
// Display the chosen order of blockers in the log
|
||||
// TODO: this is best done via a combat panel update
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(playerWhoAttacks.getName());
|
||||
sb.append(" has ordered blockers for ");
|
||||
sb.append(attacker);
|
||||
sb.append(": ");
|
||||
for (int i = 0; i < orderedBlockers.size(); i++) {
|
||||
sb.append(orderedBlockers.get(i));
|
||||
if (i != orderedBlockers.size() - 1) {
|
||||
sb.append(", ");
|
||||
}
|
||||
}
|
||||
playerWhoAttacks.getGame().getGameLog().add(GameLogEntryType.COMBAT, sb.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a blocker to the damage assignment order of an attacker. The
|
||||
* relative order of creatures already blocking the attacker may not be
|
||||
|
||||
9
forge-gui/res/cardsfolder/b/balduvian_warlord.txt
Normal file
9
forge-gui/res/cardsfolder/b/balduvian_warlord.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
Name:Balduvian Warlord
|
||||
ManaCost:3 R
|
||||
Types:Creature Human Barbarian
|
||||
PT:3/2
|
||||
A:AB$ RemoveFromCombat | Cost$ T | ActivationPhases$ Declare Blockers | ValidTgts$ Creature.blocking | Defined$ Targeted | UnblockCreaturesBlockedOnlyBy$ Targeted | SubAbility$ ChooseAttacker | SpellDescription$ Remove target blocking creature from combat. Creatures it was blocking that hadn’t become blocked by another creature this combat become unblocked.
|
||||
SVar:ChooseAttacker:DB$ ChooseCard | Defined$ You | Choices$ Creature.attacking | RememberChosen$ True | | Mandatory$ True | SubAbility$ Block
|
||||
SVar:Block:DB$ Block | DefinedAttacker$ Remembered | DefinedBlocker$ ParentTarget | SpellDescription$ Then it blocks an attacking creature of your choice. Activate this ability only during the declare blockers step.
|
||||
SVar:Picture:http://resources.wizards.com/magic/cards/tsb/en-us/card108906.jpg
|
||||
Oracle:{T}: Remove target blocking creature from combat. Creatures it was blocking that hadn’t become blocked by another creature this combat become unblocked, then it blocks an attacking creature of your choice. Activate this ability only during the declare blockers step.
|
||||
8
forge-gui/res/cardsfolder/f/false_orders.txt
Normal file
8
forge-gui/res/cardsfolder/f/false_orders.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
Name:False Orders
|
||||
ManaCost:R
|
||||
Types:Instant
|
||||
Text:Cast CARDNAME only during the declare blockers step.
|
||||
A:SP$ RemoveFromCombat | Cost$ R | ActivationPhases$ Declare Blockers | ValidTgts$ Creature.DefendingPlayerCtrl | Defined$ Targeted | UnblockCreaturesBlockedOnlyBy$ Targeted | SubAbility$ ChooseAttacker | SpellDescription$ Remove target creature defending player controls from combat. Creatures it was blocking that had become blocked by only that creature this combat become unblocked.
|
||||
SVar:ChooseAttacker:DB$ ChooseCard | Defined$ You | Choices$ Creature.attacking | RememberChosen$ True | MinAmount$ 0 | SubAbility$ Block
|
||||
SVar:Block:DB$ Block | DefinedAttacker$ Remembered | DefinedBlocker$ ParentTarget | SpellDescription$ You may have it block an attacking creature of your choice.
|
||||
Oracle:Cast this spell only during the declare blockers step.\nRemove target creature defending player controls from combat. Creatures it was blocking that had become blocked by only that creature this combat become unblocked. You may have it block an attacking creature of your choice.
|
||||
Reference in New Issue
Block a user