mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-20 12:48:00 +00:00
Invasion Plans using Timestamp instead (#5458)
* Invasion Plans using ReplacementEffect instead * StaticAbilityContinuous: use DeclaresAttackers and DeclaresBlockers with ts * update scripts * Update master_warcraft.txt * Player: update DeclaresAttacker and DeclaresBlocker with getDefinedPlayers --------- Co-authored-by: tool4ever <therealtoolkit@hotmail.com>
This commit is contained in:
@@ -69,7 +69,6 @@ public enum SpellApiToAi {
|
||||
.put(ApiType.DayTime, DayTimeAi.class)
|
||||
.put(ApiType.DealDamage, DamageDealAi.class)
|
||||
.put(ApiType.Debuff, DebuffAi.class)
|
||||
.put(ApiType.DeclareCombatants, CannotPlayAi.class)
|
||||
.put(ApiType.DelayedTrigger, DelayedTriggerAi.class)
|
||||
.put(ApiType.Destroy, DestroyAi.class)
|
||||
.put(ApiType.DestroyAll, DestroyAllAi.class)
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* 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.game;
|
||||
|
||||
/**
|
||||
* The Enum GlobalRuleChange.
|
||||
*/
|
||||
public enum GlobalRuleChange {
|
||||
|
||||
attackerChoosesBlockers ("The attacking player chooses how each creature blocks each combat.");
|
||||
|
||||
private final String ruleText;
|
||||
|
||||
GlobalRuleChange(String text) {
|
||||
ruleText = text;
|
||||
}
|
||||
|
||||
public static GlobalRuleChange fromString(String text) {
|
||||
for (final GlobalRuleChange v : GlobalRuleChange.values()) {
|
||||
if (v.ruleText.compareToIgnoreCase(text) == 0) {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
throw new RuntimeException("Element " + text + " not found in GlobalRuleChange enum");
|
||||
}
|
||||
}
|
||||
@@ -198,6 +198,9 @@ public class StaticEffect {
|
||||
p.removeAdditionalVote(getTimestamp());
|
||||
p.removeAdditionalOptionalVote(getTimestamp());
|
||||
p.removeAdditionalVillainousChoices(getTimestamp());
|
||||
|
||||
p.removeDeclaresAttackers(getTimestamp());
|
||||
p.removeDeclaresBlockers(getTimestamp());
|
||||
}
|
||||
|
||||
// modify the affected card
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
*/
|
||||
package forge.game;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -39,12 +38,8 @@ public class StaticEffects {
|
||||
|
||||
// **************** StaticAbility system **************************
|
||||
private final Map<StaticAbility, StaticEffect> staticEffects = Maps.newHashMap();
|
||||
//Global rule changes
|
||||
private final Set<GlobalRuleChange> ruleChanges = EnumSet.noneOf(GlobalRuleChange.class);
|
||||
|
||||
public final void clearStaticEffects(final Set<Card> affectedCards) {
|
||||
ruleChanges.clear();
|
||||
|
||||
// remove all static effects
|
||||
for (final StaticEffect se : staticEffects.values()) {
|
||||
Iterables.addAll(affectedCards, se.remove());
|
||||
@@ -52,14 +47,6 @@ public class StaticEffects {
|
||||
this.staticEffects.clear();
|
||||
}
|
||||
|
||||
public void setGlobalRuleChange(final GlobalRuleChange change) {
|
||||
this.ruleChanges.add(change);
|
||||
}
|
||||
|
||||
public boolean getGlobalRuleChange(final GlobalRuleChange change) {
|
||||
return this.ruleChanges.contains(change);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a static effect to the list of static effects.
|
||||
*
|
||||
|
||||
@@ -66,7 +66,6 @@ public enum ApiType {
|
||||
DealDamage (DamageDealEffect.class),
|
||||
DayTime (DayTimeEffect.class),
|
||||
Debuff (DebuffEffect.class),
|
||||
DeclareCombatants (DeclareCombatantsEffect.class),
|
||||
DelayedTrigger (DelayedTriggerEffect.class),
|
||||
Destroy (DestroyEffect.class),
|
||||
DestroyAll (DestroyAllEffect.class),
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
package forge.game.ability.effects;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import forge.GameCommand;
|
||||
import forge.game.ability.SpellAbilityEffect;
|
||||
import forge.game.phase.PhaseHandler;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.util.Lang;
|
||||
import forge.util.TextUtil;
|
||||
|
||||
public class DeclareCombatantsEffect extends SpellAbilityEffect {
|
||||
|
||||
@Override
|
||||
protected String getStackDescription(SpellAbility sa) {
|
||||
List<Player> tgtPlayers = getDefinedPlayersOrTargeted(sa);
|
||||
boolean attackers = sa.hasParam("DeclareAttackers");
|
||||
boolean blockers = sa.hasParam("DeclareBlockers");
|
||||
String what = Lang.joinHomogenous(
|
||||
attackers
|
||||
? "which creatures attack"
|
||||
: null,
|
||||
blockers
|
||||
? "which creatures block this turn and how those creatures block"
|
||||
: null
|
||||
);
|
||||
String duration = "EndOfTurn".equals(sa.getParam("Until")) ? "turn" : "combat";
|
||||
return TextUtil.concatWithSpace(Lang.joinHomogenous(tgtPlayers),Lang.joinVerb(tgtPlayers, "choose"),what,"this",TextUtil.addSuffix(duration,"."));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resolve(SpellAbility sa) {
|
||||
List<Player> tgtPlayers = getDefinedPlayersOrTargeted(sa);
|
||||
|
||||
final boolean attackers = sa.hasParam("DeclareAttackers");
|
||||
final boolean blockers = sa.hasParam("DeclareBlockers");
|
||||
|
||||
String until = sa.getParam("Until");
|
||||
boolean untilEoT = "EndOfTurn".equals(until);
|
||||
|
||||
for (Player p : tgtPlayers) { // Obviously the last player will be applied
|
||||
final PhaseHandler ph = p.getGame().getPhaseHandler();
|
||||
if (attackers) ph.setPlayerDeclaresAttackers(p);
|
||||
if (blockers) ph.setPlayerDeclaresBlockers(p);
|
||||
|
||||
GameCommand removeOverrides = new GameCommand() {
|
||||
private static final long serialVersionUID = -8064627517852651016L;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (attackers) ph.setPlayerDeclaresAttackers(null);
|
||||
if (blockers) ph.setPlayerDeclaresBlockers(null);
|
||||
}
|
||||
};
|
||||
|
||||
if (untilEoT)
|
||||
p.getGame().getEndOfTurn().addUntil(removeOverrides);
|
||||
else
|
||||
p.getGame().getEndOfCombat().addUntil(removeOverrides);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -44,8 +44,6 @@ public class RestartGameEffect extends SpellAbilityEffect {
|
||||
trigHandler.suppressMode(TriggerType.Shuffled);
|
||||
|
||||
game.getPhaseHandler().restart();
|
||||
game.getPhaseHandler().setPlayerDeclaresAttackers(null);
|
||||
game.getPhaseHandler().setPlayerDeclaresBlockers(null);
|
||||
game.getUntap().clearCommands();
|
||||
game.getUpkeep().clearCommands();
|
||||
game.getEndOfCombat().clearCommands();
|
||||
|
||||
@@ -45,6 +45,8 @@ import forge.util.CollectionSuppliers;
|
||||
import forge.util.TextUtil;
|
||||
import forge.util.maps.HashMapOfLists;
|
||||
import forge.util.maps.MapOfLists;
|
||||
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.time.StopWatch;
|
||||
|
||||
import java.util.*;
|
||||
@@ -84,9 +86,6 @@ public class PhaseHandler implements java.io.Serializable {
|
||||
private transient Combat combat = null;
|
||||
private boolean bRepeatCleanup = false;
|
||||
|
||||
private transient Player playerDeclaresBlockers = null;
|
||||
private transient Player playerDeclaresAttackers = null;
|
||||
|
||||
/** The need to next phase. */
|
||||
private boolean givePriorityToPlayer = false;
|
||||
|
||||
@@ -523,9 +522,7 @@ public class PhaseHandler implements java.io.Serializable {
|
||||
}
|
||||
|
||||
private void declareAttackersTurnBasedAction() {
|
||||
final Player whoDeclares = playerDeclaresAttackers == null || playerDeclaresAttackers.hasLost()
|
||||
? playerTurn
|
||||
: playerDeclaresAttackers;
|
||||
final Player whoDeclares = ObjectUtils.firstNonNull(playerTurn.getDeclaresAttackers(), playerTurn);
|
||||
|
||||
if (CombatUtil.canAttack(playerTurn)) {
|
||||
boolean success = false;
|
||||
@@ -653,10 +650,7 @@ public class PhaseHandler implements java.io.Serializable {
|
||||
do {
|
||||
p = game.getNextPlayerAfter(p);
|
||||
// Apply Odric's effect here
|
||||
Player whoDeclaresBlockers = playerDeclaresBlockers == null || playerDeclaresBlockers.hasLost() ? p : playerDeclaresBlockers;
|
||||
if (game.getStaticEffects().getGlobalRuleChange(GlobalRuleChange.attackerChoosesBlockers)) {
|
||||
whoDeclaresBlockers = combat.getAttackingPlayer();
|
||||
}
|
||||
Player whoDeclaresBlockers = ObjectUtils.firstNonNull(p.getDeclaresBlockers(), p);
|
||||
if (combat.isPlayerAttacked(p)) {
|
||||
if (CombatUtil.canBlock(p, combat)) {
|
||||
// Replacement effects (for Camouflage)
|
||||
@@ -1235,14 +1229,6 @@ public class PhaseHandler implements java.io.Serializable {
|
||||
givePriorityToPlayer = true;
|
||||
}
|
||||
|
||||
public final void setPlayerDeclaresAttackers(Player player) {
|
||||
playerDeclaresAttackers = player;
|
||||
}
|
||||
|
||||
public final void setPlayerDeclaresBlockers(Player player) {
|
||||
playerDeclaresBlockers = player;
|
||||
}
|
||||
|
||||
public void endCombat() {
|
||||
game.getEndOfCombat().executeUntil();
|
||||
game.getEndOfCombat().executeUntilEndOfPhase(playerTurn);
|
||||
|
||||
@@ -194,6 +194,9 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
private SortedSet<Long> controlVotes = Sets.newTreeSet();
|
||||
private Map<Long, Integer> additionalVillainousChoices = Maps.newHashMap();
|
||||
|
||||
private NavigableMap<Long, Player> declaresAttackers = Maps.newTreeMap();
|
||||
private NavigableMap<Long, Player> declaresBlockers = Maps.newTreeMap();
|
||||
|
||||
private final AchievementTracker achievementTracker = new AchievementTracker();
|
||||
private final PlayerView view;
|
||||
|
||||
@@ -3814,4 +3817,30 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
public void setCommitedCrimeThisTurn(int v) {
|
||||
committedCrimeThisTurn = v;
|
||||
}
|
||||
|
||||
public void addDeclaresAttackers(long ts, Player p) {
|
||||
this.declaresAttackers.put(ts, p);
|
||||
}
|
||||
|
||||
public void removeDeclaresAttackers(long ts) {
|
||||
this.declaresAttackers.remove(ts);
|
||||
}
|
||||
|
||||
public Player getDeclaresAttackers() {
|
||||
Map.Entry<Long, Player> e = declaresAttackers.lastEntry();
|
||||
return e == null ? null : e.getValue();
|
||||
}
|
||||
|
||||
public void addDeclaresBlockers(long ts, Player p) {
|
||||
this.declaresBlockers.put(ts, p);
|
||||
}
|
||||
|
||||
public void removeDeclaresBlockers(long ts) {
|
||||
this.declaresBlockers.remove(ts);
|
||||
}
|
||||
|
||||
public Player getDeclaresBlockers() {
|
||||
Map.Entry<Long, Player> e = declaresBlockers.lastEntry();
|
||||
return e == null ? null : e.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,6 +175,10 @@ public class PlayerProperty {
|
||||
if (!source.getDamageHistory().hasAttackedThisTurn(player)) {
|
||||
return false;
|
||||
}
|
||||
} else if (property.equals("Attacking")) {
|
||||
if (game.getCombat() == null || !player.equals(game.getCombat().getAttackingPlayer())) {
|
||||
return false;
|
||||
}
|
||||
} else if (property.equals("Defending")) {
|
||||
if (game.getCombat() == null || !game.getCombat().getAttackersAndDefenders().values().contains(player)) {
|
||||
return false;
|
||||
|
||||
@@ -165,7 +165,8 @@ public class StaticAbility extends CardTraitBase implements IIdentifiable, Clone
|
||||
|
||||
if (hasParam("AddHiddenKeyword") || hasParam("MayPlay")
|
||||
|| hasParam("IgnoreEffectCost") || hasParam("Goad") || hasParam("CanBlockAny") || hasParam("CanBlockAmount")
|
||||
|| hasParam("AdjustLandPlays") || hasParam("ControlVote") || hasParam("AdditionalVote") || hasParam("AdditionalOptionalVote")) {
|
||||
|| hasParam("AdjustLandPlays") || hasParam("ControlVote") || hasParam("AdditionalVote") || hasParam("AdditionalOptionalVote")
|
||||
|| hasParam("DeclaresAttackers") || hasParam("DeclaresBlockers")) {
|
||||
layers.add(StaticAbilityLayer.RULES);
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ import com.google.common.collect.Maps;
|
||||
import forge.GameCommand;
|
||||
import forge.card.*;
|
||||
import forge.game.Game;
|
||||
import forge.game.GlobalRuleChange;
|
||||
import forge.game.StaticEffect;
|
||||
import forge.game.StaticEffects;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
@@ -142,11 +141,6 @@ public final class StaticAbilityContinuous {
|
||||
boolean mayPlayGrantZonePermissions = true;
|
||||
Integer mayPlayLimit = null;
|
||||
|
||||
//Global rules changes
|
||||
if (layer == StaticAbilityLayer.RULES && params.containsKey("GlobalRule")) {
|
||||
effects.setGlobalRuleChange(GlobalRuleChange.fromString(params.get("GlobalRule")));
|
||||
}
|
||||
|
||||
if (layer == StaticAbilityLayer.SETPT || layer == StaticAbilityLayer.CHARACTERISTIC) {
|
||||
if (params.containsKey("SetPower")) {
|
||||
setP = params.get("SetPower");
|
||||
@@ -599,6 +593,17 @@ public final class StaticAbilityContinuous {
|
||||
int add = AbilityUtils.calculateAmount(hostCard, mhs, stAb);
|
||||
p.addAdditionalVillainousChoices(se.getTimestamp(), add);
|
||||
}
|
||||
|
||||
if (params.containsKey("DeclaresAttackers")) {
|
||||
PlayerCollection players = AbilityUtils.getDefinedPlayers(hostCard, params.get("DeclaresAttackers"), stAb);
|
||||
if (!players.isEmpty())
|
||||
p.addDeclaresAttackers(se.getTimestamp(), players.getFirst());
|
||||
}
|
||||
if (params.containsKey("DeclaresBlockers")) {
|
||||
PlayerCollection players = AbilityUtils.getDefinedPlayers(hostCard, params.get("DeclaresBlockers"), stAb);
|
||||
if (!players.isEmpty())
|
||||
p.addDeclaresBlockers(se.getTimestamp(), players.getFirst());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,5 +6,6 @@ SVar:MustBlock:DB$ ChooseCard | Choices$ Creature | Amount$ X | MinAmount$ 0 | C
|
||||
SVar:DBEffect:DB$ Effect | StaticAbilities$ StaticBlock
|
||||
SVar:StaticBlock:Mode$ MustBlock | ValidCreature$ Card.ChosenCardStrict | Description$ The chosen creatures block this turn if able.
|
||||
SVar:X:Count$Valid Creature
|
||||
SVar:ChooseBlock:DB$ DeclareCombatants | DeclareBlockers$ True | Until$ EndOfTurn | SpellDescription$ 15—20 VERT You choose which creatures block this turn and how those creatures block.
|
||||
SVar:ChooseBlock:DB$ Effect | StaticAbilities$ DeclareCombatants | SpellDescription$ 15—20 VERT You choose which creatures block this turn and how those creatures block.
|
||||
SVar:DeclareCombatants:Mode$ Continuous | Affected$ Player | DeclaresBlockers$ You | Description$ You choose which creatures block this combat and how those creatures block.
|
||||
Oracle:Cast this spell only before combat or during combat before blockers are declared.\nRoll two d20 and ignore the lower roll.\n1—14 | Choose any number of creatures. They block this turn if able.\n15—20 | You choose which creatures block this turn and how those creatures block.
|
||||
|
||||
@@ -5,9 +5,9 @@ PT:3/3
|
||||
T:Mode$ Attacks | ValidCard$ Creature.YouCtrl | TriggerZones$ Battlefield | Execute$ TrigLoseLife | TriggerDescription$ Whenever a creature you control attacks, defending player loses 1 life and you gain 1 life.
|
||||
SVar:TrigLoseLife:DB$ LoseLife | Defined$ TriggeredDefendingPlayer | LifeAmount$ 1 | SubAbility$ DBGainLife
|
||||
SVar:DBGainLife:DB$ GainLife | LifeAmount$ 1
|
||||
A:AB$ Effect | Cost$ 3 RW RW | StaticAbilities$ STBlock | SubAbility$ DBDeclareCombatants | SpellDescription$ Creatures your opponents control block this turn if able, and you choose how those creatures block.
|
||||
A:AB$ Effect | Cost$ 3 RW RW | StaticAbilities$ STBlock,DeclareCombatants | SpellDescription$ Creatures your opponents control block this turn if able, and you choose how those creatures block.
|
||||
SVar:STBlock:Mode$ MustBlock | ValidCreature$ Creature.OppCtrl | Description$ Creatures your opponents control block this turn if able, and you choose how those creatures block.
|
||||
SVar:DBDeclareCombatants:DB$ DeclareCombatants | DeclareBlockers$ True | Until$ EndOfTurn
|
||||
SVar:DeclareCombatants:Mode$ Continuous | Affected$ Player.Opponent | DeclaresBlockers$ You | Description$ You choose how those creatures block.
|
||||
SVar:HasAttackEffect:TRUE
|
||||
DeckHas:Ability$LifeGain
|
||||
Oracle:Whenever a creature you control attacks, defending player loses 1 life and you gain 1 life.\n{3}{R/W}{R/W}: Creatures your opponents control block this turn if able, and you choose how those creatures block.
|
||||
|
||||
@@ -2,7 +2,7 @@ Name:Invasion Plans
|
||||
ManaCost:2 R
|
||||
Types:Enchantment
|
||||
S:Mode$ MustBlock | ValidCreature$ Creature | Description$ All creatures block each combat if able.
|
||||
S:Mode$ Continuous | GlobalRule$ The attacking player chooses how each creature blocks each combat. | Description$ The attacking player chooses how each creature blocks each combat.
|
||||
S:Mode$ Continuous | Affected$ Player | DeclaresBlockers$ AttackingPlayer | Description$ The attacking player chooses how each creature blocks each combat.
|
||||
SVar:NonStackingEffect:True
|
||||
AI:RemoveDeck:Random
|
||||
Oracle:All creatures block each combat if able.\nThe attacking player chooses how each creature blocks each combat.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
Name:Master Warcraft
|
||||
ManaCost:2 RW RW
|
||||
Types:Instant
|
||||
A:SP$ DeclareCombatants | DeclareAttackers$ True | DeclareBlockers$ True | ActivationPhases$ Upkeep->BeginCombat | ActivationFirstCombat$ True | Until$ EndOfTurn | SpellDescription$ Cast this spell only before attackers are declared. You choose which creatures attack this turn. You choose which creatures block this turn and how those creatures block.
|
||||
A:SP$ Effect | StaticAbilities$ DeclareCombatants | ActivationPhases$ Upkeep->BeginCombat | ActivationFirstCombat$ True | SpellDescription$ Cast this spell only before attackers are declared. You choose which creatures attack this turn. You choose which creatures block this turn and how those creatures block.
|
||||
SVar:DeclareCombatants:Mode$ Continuous | Affected$ Player | DeclaresAttackers$ You | DeclaresBlockers$ You | Description$ You choose which creatures attack this turn. You choose which creatures block this turn and how those creatures block.
|
||||
AI:RemoveDeck:All
|
||||
Oracle:Cast this spell only before attackers are declared.\nYou choose which creatures attack this turn.\nYou choose which creatures block this turn and how those creatures block.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
Name:Melee
|
||||
ManaCost:4 R
|
||||
Types:Instant
|
||||
A:SP$ DeclareCombatants | DeclareBlockers$ True | PlayerTurn$ True | ActivationPhases$ BeginCombat->Declare Attackers | SubAbility$ DBEffect | SpellDescription$ Cast this spell only during your turn and only during combat before blockers are declared. You choose which creatures block this combat and how those creatures block. Whenever a creature attacks and isn't blocked this combat, untap it and remove it from combat.
|
||||
SVar:DBEffect:DB$ Effect | Triggers$ TrigAttack | Duration$ UntilEndOfCombat
|
||||
A:SP$ Effect | StaticAbilities$ DeclareCombatants | Triggers$ TrigAttack | Duration$ UntilEndOfCombat | PlayerTurn$ True | ActivationPhases$ BeginCombat->Declare Attackers | SpellDescription$ Cast this spell only during your turn and only during combat before blockers are declared. You choose which creatures block this combat and how those creatures block. Whenever a creature attacks and isn't blocked this combat, untap it and remove it from combat.
|
||||
SVar:DeclareCombatants:Mode$ Continuous | Affected$ Player | DeclaresBlockers$ You | Description$ You choose which creatures block this combat and how those creatures block.
|
||||
SVar:TrigAttack:Mode$ AttackerUnblocked | ValidCard$ Creature | Execute$ TrigUntap | TriggerZones$ Command | TriggerDescription$ Whenever a creature attacks and isn't blocked this combat, untap it and remove it from combat.
|
||||
SVar:TrigUntap:DB$ Untap | Defined$ TriggeredAttackerLKICopy | SubAbility$ RemCombat
|
||||
SVar:RemCombat:DB$ RemoveFromCombat | Defined$ TriggeredAttackerLKICopy
|
||||
|
||||
@@ -4,6 +4,7 @@ Types:Legendary Creature Human Soldier
|
||||
PT:3/4
|
||||
K:First Strike
|
||||
T:Mode$ Attacks | ValidCard$ Card.Self | TriggerZones$ Battlefield | IsPresent$ Creature.attacking+Other | PresentCompare$ GE3 | NoResolvingCheck$ True | Execute$ TrigOdricEffect | TriggerDescription$ Whenever CARDNAME and at least three other creatures attack, you choose which creatures block this combat and how those creatures block.
|
||||
SVar:TrigOdricEffect:DB$ DeclareCombatants | DeclareBlockers$ True
|
||||
SVar:TrigOdricEffect:DB$ Effect | StaticAbilities$ DeclareCombatants | Duration$ UntilEndOfCombat
|
||||
SVar:DeclareCombatants:Mode$ Continuous | Affected$ Player | DeclaresBlockers$ You | Description$ You choose which creatures block this combat and how those creatures block.
|
||||
AI:RemoveDeck:All
|
||||
Oracle:First strike (This creature deals combat damage before creatures without first strike.)\nWhenever Odric, Master Tactician and at least three other creatures attack, you choose which creatures block this combat and how those creatures block.
|
||||
|
||||
Reference in New Issue
Block a user