BlockEffect and related cards

This commit is contained in:
apantel
2019-06-01 00:05:41 -04:00
parent 6bbc8d54df
commit 9b1d500073
5 changed files with 154 additions and 19 deletions

View File

@@ -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),

View File

@@ -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();
}
}

View File

@@ -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

View 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 hadnt 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 hadnt 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.

View 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.