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:
Hans Mackowiak
2024-06-24 13:48:20 +02:00
committed by GitHub
parent fe7043dd0d
commit d5ab4be451
18 changed files with 66 additions and 159 deletions

View File

@@ -69,7 +69,6 @@ public enum SpellApiToAi {
.put(ApiType.DayTime, DayTimeAi.class) .put(ApiType.DayTime, DayTimeAi.class)
.put(ApiType.DealDamage, DamageDealAi.class) .put(ApiType.DealDamage, DamageDealAi.class)
.put(ApiType.Debuff, DebuffAi.class) .put(ApiType.Debuff, DebuffAi.class)
.put(ApiType.DeclareCombatants, CannotPlayAi.class)
.put(ApiType.DelayedTrigger, DelayedTriggerAi.class) .put(ApiType.DelayedTrigger, DelayedTriggerAi.class)
.put(ApiType.Destroy, DestroyAi.class) .put(ApiType.Destroy, DestroyAi.class)
.put(ApiType.DestroyAll, DestroyAllAi.class) .put(ApiType.DestroyAll, DestroyAllAi.class)

View File

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

View File

@@ -198,6 +198,9 @@ public class StaticEffect {
p.removeAdditionalVote(getTimestamp()); p.removeAdditionalVote(getTimestamp());
p.removeAdditionalOptionalVote(getTimestamp()); p.removeAdditionalOptionalVote(getTimestamp());
p.removeAdditionalVillainousChoices(getTimestamp()); p.removeAdditionalVillainousChoices(getTimestamp());
p.removeDeclaresAttackers(getTimestamp());
p.removeDeclaresBlockers(getTimestamp());
} }
// modify the affected card // modify the affected card

View File

@@ -17,7 +17,6 @@
*/ */
package forge.game; package forge.game;
import java.util.EnumSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@@ -39,12 +38,8 @@ public class StaticEffects {
// **************** StaticAbility system ************************** // **************** StaticAbility system **************************
private final Map<StaticAbility, StaticEffect> staticEffects = Maps.newHashMap(); 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) { public final void clearStaticEffects(final Set<Card> affectedCards) {
ruleChanges.clear();
// remove all static effects // remove all static effects
for (final StaticEffect se : staticEffects.values()) { for (final StaticEffect se : staticEffects.values()) {
Iterables.addAll(affectedCards, se.remove()); Iterables.addAll(affectedCards, se.remove());
@@ -52,14 +47,6 @@ public class StaticEffects {
this.staticEffects.clear(); 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. * Add a static effect to the list of static effects.
* *

View File

@@ -66,7 +66,6 @@ public enum ApiType {
DealDamage (DamageDealEffect.class), DealDamage (DamageDealEffect.class),
DayTime (DayTimeEffect.class), DayTime (DayTimeEffect.class),
Debuff (DebuffEffect.class), Debuff (DebuffEffect.class),
DeclareCombatants (DeclareCombatantsEffect.class),
DelayedTrigger (DelayedTriggerEffect.class), DelayedTrigger (DelayedTriggerEffect.class),
Destroy (DestroyEffect.class), Destroy (DestroyEffect.class),
DestroyAll (DestroyAllEffect.class), DestroyAll (DestroyAllEffect.class),

View File

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

View File

@@ -44,8 +44,6 @@ public class RestartGameEffect extends SpellAbilityEffect {
trigHandler.suppressMode(TriggerType.Shuffled); trigHandler.suppressMode(TriggerType.Shuffled);
game.getPhaseHandler().restart(); game.getPhaseHandler().restart();
game.getPhaseHandler().setPlayerDeclaresAttackers(null);
game.getPhaseHandler().setPlayerDeclaresBlockers(null);
game.getUntap().clearCommands(); game.getUntap().clearCommands();
game.getUpkeep().clearCommands(); game.getUpkeep().clearCommands();
game.getEndOfCombat().clearCommands(); game.getEndOfCombat().clearCommands();

View File

@@ -45,6 +45,8 @@ import forge.util.CollectionSuppliers;
import forge.util.TextUtil; import forge.util.TextUtil;
import forge.util.maps.HashMapOfLists; import forge.util.maps.HashMapOfLists;
import forge.util.maps.MapOfLists; import forge.util.maps.MapOfLists;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.time.StopWatch; import org.apache.commons.lang3.time.StopWatch;
import java.util.*; import java.util.*;
@@ -84,9 +86,6 @@ public class PhaseHandler implements java.io.Serializable {
private transient Combat combat = null; private transient Combat combat = null;
private boolean bRepeatCleanup = false; private boolean bRepeatCleanup = false;
private transient Player playerDeclaresBlockers = null;
private transient Player playerDeclaresAttackers = null;
/** The need to next phase. */ /** The need to next phase. */
private boolean givePriorityToPlayer = false; private boolean givePriorityToPlayer = false;
@@ -523,9 +522,7 @@ public class PhaseHandler implements java.io.Serializable {
} }
private void declareAttackersTurnBasedAction() { private void declareAttackersTurnBasedAction() {
final Player whoDeclares = playerDeclaresAttackers == null || playerDeclaresAttackers.hasLost() final Player whoDeclares = ObjectUtils.firstNonNull(playerTurn.getDeclaresAttackers(), playerTurn);
? playerTurn
: playerDeclaresAttackers;
if (CombatUtil.canAttack(playerTurn)) { if (CombatUtil.canAttack(playerTurn)) {
boolean success = false; boolean success = false;
@@ -653,10 +650,7 @@ public class PhaseHandler implements java.io.Serializable {
do { do {
p = game.getNextPlayerAfter(p); p = game.getNextPlayerAfter(p);
// Apply Odric's effect here // Apply Odric's effect here
Player whoDeclaresBlockers = playerDeclaresBlockers == null || playerDeclaresBlockers.hasLost() ? p : playerDeclaresBlockers; Player whoDeclaresBlockers = ObjectUtils.firstNonNull(p.getDeclaresBlockers(), p);
if (game.getStaticEffects().getGlobalRuleChange(GlobalRuleChange.attackerChoosesBlockers)) {
whoDeclaresBlockers = combat.getAttackingPlayer();
}
if (combat.isPlayerAttacked(p)) { if (combat.isPlayerAttacked(p)) {
if (CombatUtil.canBlock(p, combat)) { if (CombatUtil.canBlock(p, combat)) {
// Replacement effects (for Camouflage) // Replacement effects (for Camouflage)
@@ -1235,14 +1229,6 @@ public class PhaseHandler implements java.io.Serializable {
givePriorityToPlayer = true; givePriorityToPlayer = true;
} }
public final void setPlayerDeclaresAttackers(Player player) {
playerDeclaresAttackers = player;
}
public final void setPlayerDeclaresBlockers(Player player) {
playerDeclaresBlockers = player;
}
public void endCombat() { public void endCombat() {
game.getEndOfCombat().executeUntil(); game.getEndOfCombat().executeUntil();
game.getEndOfCombat().executeUntilEndOfPhase(playerTurn); game.getEndOfCombat().executeUntilEndOfPhase(playerTurn);

View File

@@ -194,6 +194,9 @@ public class Player extends GameEntity implements Comparable<Player> {
private SortedSet<Long> controlVotes = Sets.newTreeSet(); private SortedSet<Long> controlVotes = Sets.newTreeSet();
private Map<Long, Integer> additionalVillainousChoices = Maps.newHashMap(); 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 AchievementTracker achievementTracker = new AchievementTracker();
private final PlayerView view; private final PlayerView view;
@@ -904,7 +907,7 @@ public class Player extends GameEntity implements Comparable<Player> {
setCounters(counterName, newValue, null, true); setCounters(counterName, newValue, null, true);
getGame().addCounterRemovedThisTurn(counterName, this, delta); getGame().addCounterRemovedThisTurn(counterName, this, delta);
/* TODO Run triggers when something cares /* TODO Run triggers when something cares
int curCounters = oldValue; int curCounters = oldValue;
for (int i = 0; i < delta && curCounters != 0; i++) { for (int i = 0; i < delta && curCounters != 0; i++) {
@@ -2301,7 +2304,7 @@ public class Player extends GameEntity implements Comparable<Player> {
public final void addSpellCastSinceBegOfYourLastTurn(List<Card> spells) { public final void addSpellCastSinceBegOfYourLastTurn(List<Card> spells) {
spellsCastSinceBeginningOfLastTurn.addAll(spells); spellsCastSinceBeginningOfLastTurn.addAll(spells);
} }
public final int getSpellsCastThisTurn() { public final int getSpellsCastThisTurn() {
return spellsCastThisTurn; return spellsCastThisTurn;
} }
@@ -3814,4 +3817,30 @@ public class Player extends GameEntity implements Comparable<Player> {
public void setCommitedCrimeThisTurn(int v) { public void setCommitedCrimeThisTurn(int v) {
committedCrimeThisTurn = 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();
}
} }

View File

@@ -175,6 +175,10 @@ public class PlayerProperty {
if (!source.getDamageHistory().hasAttackedThisTurn(player)) { if (!source.getDamageHistory().hasAttackedThisTurn(player)) {
return false; return false;
} }
} else if (property.equals("Attacking")) {
if (game.getCombat() == null || !player.equals(game.getCombat().getAttackingPlayer())) {
return false;
}
} else if (property.equals("Defending")) { } else if (property.equals("Defending")) {
if (game.getCombat() == null || !game.getCombat().getAttackersAndDefenders().values().contains(player)) { if (game.getCombat() == null || !game.getCombat().getAttackersAndDefenders().values().contains(player)) {
return false; return false;

View File

@@ -165,7 +165,8 @@ public class StaticAbility extends CardTraitBase implements IIdentifiable, Clone
if (hasParam("AddHiddenKeyword") || hasParam("MayPlay") if (hasParam("AddHiddenKeyword") || hasParam("MayPlay")
|| hasParam("IgnoreEffectCost") || hasParam("Goad") || hasParam("CanBlockAny") || hasParam("CanBlockAmount") || 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); layers.add(StaticAbilityLayer.RULES);
} }

View File

@@ -26,7 +26,6 @@ import com.google.common.collect.Maps;
import forge.GameCommand; import forge.GameCommand;
import forge.card.*; import forge.card.*;
import forge.game.Game; import forge.game.Game;
import forge.game.GlobalRuleChange;
import forge.game.StaticEffect; import forge.game.StaticEffect;
import forge.game.StaticEffects; import forge.game.StaticEffects;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
@@ -142,11 +141,6 @@ public final class StaticAbilityContinuous {
boolean mayPlayGrantZonePermissions = true; boolean mayPlayGrantZonePermissions = true;
Integer mayPlayLimit = null; 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 (layer == StaticAbilityLayer.SETPT || layer == StaticAbilityLayer.CHARACTERISTIC) {
if (params.containsKey("SetPower")) { if (params.containsKey("SetPower")) {
setP = params.get("SetPower"); setP = params.get("SetPower");
@@ -599,6 +593,17 @@ public final class StaticAbilityContinuous {
int add = AbilityUtils.calculateAmount(hostCard, mhs, stAb); int add = AbilityUtils.calculateAmount(hostCard, mhs, stAb);
p.addAdditionalVillainousChoices(se.getTimestamp(), add); 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());
}
} }
} }

View File

@@ -6,5 +6,6 @@ SVar:MustBlock:DB$ ChooseCard | Choices$ Creature | Amount$ X | MinAmount$ 0 | C
SVar:DBEffect:DB$ Effect | StaticAbilities$ StaticBlock SVar:DBEffect:DB$ Effect | StaticAbilities$ StaticBlock
SVar:StaticBlock:Mode$ MustBlock | ValidCreature$ Card.ChosenCardStrict | Description$ The chosen creatures block this turn if able. SVar:StaticBlock:Mode$ MustBlock | ValidCreature$ Card.ChosenCardStrict | Description$ The chosen creatures block this turn if able.
SVar:X:Count$Valid Creature 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. 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.

View File

@@ -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. 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:TrigLoseLife:DB$ LoseLife | Defined$ TriggeredDefendingPlayer | LifeAmount$ 1 | SubAbility$ DBGainLife
SVar:DBGainLife:DB$ GainLife | LifeAmount$ 1 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: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 SVar:HasAttackEffect:TRUE
DeckHas:Ability$LifeGain 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. 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.

View File

@@ -2,7 +2,7 @@ Name:Invasion Plans
ManaCost:2 R ManaCost:2 R
Types:Enchantment Types:Enchantment
S:Mode$ MustBlock | ValidCreature$ Creature | Description$ All creatures block each combat if able. 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 SVar:NonStackingEffect:True
AI:RemoveDeck:Random AI:RemoveDeck:Random
Oracle:All creatures block each combat if able.\nThe attacking player chooses how each creature blocks each combat. Oracle:All creatures block each combat if able.\nThe attacking player chooses how each creature blocks each combat.

View File

@@ -1,6 +1,7 @@
Name:Master Warcraft Name:Master Warcraft
ManaCost:2 RW RW ManaCost:2 RW RW
Types:Instant 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 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. 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.

View File

@@ -1,8 +1,8 @@
Name:Melee Name:Melee
ManaCost:4 R ManaCost:4 R
Types:Instant 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. 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:DBEffect:DB$ Effect | Triggers$ TrigAttack | Duration$ UntilEndOfCombat 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: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:TrigUntap:DB$ Untap | Defined$ TriggeredAttackerLKICopy | SubAbility$ RemCombat
SVar:RemCombat:DB$ RemoveFromCombat | Defined$ TriggeredAttackerLKICopy SVar:RemCombat:DB$ RemoveFromCombat | Defined$ TriggeredAttackerLKICopy

View File

@@ -4,6 +4,7 @@ Types:Legendary Creature Human Soldier
PT:3/4 PT:3/4
K:First Strike 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. 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 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. 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.