mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-18 11:48:02 +00:00
Merge branch 'master' into Attractions
# Conflicts: # forge-game/src/main/java/forge/game/player/Player.java
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.
|
||||
*
|
||||
|
||||
@@ -67,7 +67,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();
|
||||
|
||||
@@ -42,6 +42,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.*;
|
||||
@@ -81,9 +83,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;
|
||||
|
||||
@@ -524,9 +523,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;
|
||||
@@ -654,10 +651,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)
|
||||
@@ -1236,14 +1230,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);
|
||||
|
||||
@@ -196,6 +196,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;
|
||||
|
||||
@@ -906,7 +909,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
setCounters(counterName, newValue, null, true);
|
||||
|
||||
getGame().addCounterRemovedThisTurn(counterName, this, delta);
|
||||
|
||||
|
||||
/* TODO Run triggers when something cares
|
||||
int curCounters = oldValue;
|
||||
for (int i = 0; i < delta && curCounters != 0; i++) {
|
||||
@@ -2303,7 +2306,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
public final void addSpellCastSinceBegOfYourLastTurn(List<Card> spells) {
|
||||
spellsCastSinceBeginningOfLastTurn.addAll(spells);
|
||||
}
|
||||
|
||||
|
||||
public final int getSpellsCastThisTurn() {
|
||||
return spellsCastThisTurn;
|
||||
}
|
||||
@@ -3894,4 +3897,30 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
|
||||
this.visitAttractions(total);
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
<objectgroup id="4" name="Objects">
|
||||
<object id="66" template="../../obj/door_up.tx" x="543" y="638">
|
||||
<properties>
|
||||
<property name="teleport" value="maps/map/cave/cave_kobold.tmx"/>
|
||||
<property name="teleport" value="../common/maps/map/cave/cave_kobold.tmx"/>
|
||||
<property name="teleportObjectId" value="67"/>
|
||||
</properties>
|
||||
</object>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<objectgroup id="4" name="Objects">
|
||||
<object id="38" template="../../obj/entry_up.tx" x="450.334" y="239.188">
|
||||
<properties>
|
||||
<property name="direction" value="down"/>
|
||||
<property name="teleport" value="../common/maps/map/fort/fort_colorless_7_multilevel4.tmx"/>
|
||||
<property name="teleportObjectId" value="38"/>
|
||||
</properties>
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
Name:Desmond Miles
|
||||
ManaCost:1 B
|
||||
Types:Legendary Creature Human Assassin
|
||||
PT:1/3
|
||||
K:Menace
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
Name:Evie Frye
|
||||
ManaCost:1 B
|
||||
Types:Legendary Creature Human Assassin
|
||||
PT:2/1
|
||||
K:Partner:Jacob Frye
|
||||
|
||||
@@ -4,7 +4,7 @@ Types:Enchantment Saga
|
||||
K:Chapter:3:DBToken,DBVote,DBVote
|
||||
SVar:DBToken:DB$ Token | TokenAmount$ OneEach | TokenScript$ w_1_1_human_soldier
|
||||
SVar:OneEach:PlayerCountOpponents$Amount
|
||||
SVar:DBVote:DB$ Vote | Defined$ Player | Secretly$ True | VoteCard$ Creature | VoteMessage$ for a creature | UpTo$ True | VoteSubAbility$ DBDestroyAll | SubAbility$ DBBranch | SpellDescription$ Each player secretly votes for up to one creature, then those votes are revealed. If no creature got votes, each player draws a card. Otherwise, destroy each creature with the most votes or tied for most votes.
|
||||
SVar:DBVote:DB$ Vote | Defined$ Player | Secretly$ True | VoteCard$ Creature | VoteMessage$ for a creature | UpTo$ True | VoteSubAbility$ DBDestroyAll | SpellDescription$ Each player secretly votes for up to one creature, then those votes are revealed. If no creature got votes, each player draws a card. Otherwise, destroy each creature with the most votes or tied for most votes.
|
||||
SVar:DBDestroyAll:DB$ DestroyAll | ValidCards$ Creature.IsRemembered | SubAbility$ DBDraw
|
||||
SVar:DBDraw:DB$ Draw | Defined$ Player | NumCards$ 1 | ConditionCheckSVar$ X | ConditionSVarCompare$ EQ0
|
||||
SVar:X:Remembered$Amount
|
||||
|
||||
@@ -3,6 +3,12 @@ Code=MH3
|
||||
Date=2024-06-07
|
||||
Name=Modern Horizons 3
|
||||
Type=Draft
|
||||
Booster=6 Common, 3 Uncommon, 1 RareMythic, 1 fromSheet("MH3 new to modern"), 1 Land, 1 Any, 1 Any+
|
||||
# This isn't the right ratios yet. But it's a start
|
||||
ChanceReplaceCommonWith=.0156F fromsheet("MH3 special guests")
|
||||
BoosterBox=36
|
||||
BoosterCovers=3
|
||||
ChaosDraftThemes=MASTERS_SET
|
||||
ScryfallCode=MH3
|
||||
|
||||
[cards]
|
||||
@@ -536,6 +542,62 @@ ScryfallCode=MH3
|
||||
495 R Powerbalance @Liiga Smilshkalne
|
||||
496 R Flusterstorm @Andrew Mar
|
||||
|
||||
[new to modern]
|
||||
1 Angel of the Ruins|MH3
|
||||
1 Decree of Justice|MH3
|
||||
1 Distinguished Conjurer|MH3
|
||||
1 Orim's Chant|MH3
|
||||
1 Recruiter of the Guard|MH3
|
||||
1 Sevinne's Reclamation|MH3
|
||||
1 Deep Analysis|MH3
|
||||
1 Estrid's Invocation|MH3
|
||||
1 Kappa Cannoneer|MH3
|
||||
1 Reef Worm|MH3
|
||||
1 Shrieking Drake|MH3
|
||||
1 Buried Alive|MH3
|
||||
1 K'rrik, Son of Yawgmoth|MH3
|
||||
1 Nadier's Nightblade|MH3
|
||||
1 Ophiomancer|MH3
|
||||
1 Toxic Deluge|MH3
|
||||
1 Victimize|MH3
|
||||
1 Cursed Mirror|MH3
|
||||
1 Fledgling Dragon|MH3
|
||||
1 Laelia, the Blade Reforged|MH3
|
||||
1 Meltdown|MH3
|
||||
1 Meteoric Mace|MH3
|
||||
1 Annoyed Altisaur|MH3
|
||||
1 Branching Evolution|MH3
|
||||
1 Priest of Titania|MH3
|
||||
1 Sylvan Safekeeper|MH3
|
||||
1 Wirewood Symbiote|MH3
|
||||
1 Breya, Etherium Shaper|MH3
|
||||
1 Kaalia of the Vast|MH3
|
||||
1 Emerald Medallion|MH3
|
||||
1 Jet Medallion|MH3
|
||||
1 Junk Diver|MH3
|
||||
1 Pearl Medallion|MH3
|
||||
1 Ruby Medallion|MH3
|
||||
1 Sapphire Medallion|MH3
|
||||
1 Urza's Incubator|MH3
|
||||
1 Worn Powerstone|MH3
|
||||
1 Barbarian Ring|MH3
|
||||
1 Cephalid Coliseum|MH3
|
||||
1 Deserted Temple|MH3
|
||||
1 Nesting Grounds|MH3
|
||||
1 Phyrexian Tower|MH3
|
||||
|
||||
[special guests]
|
||||
1 Thought-Knot Seer|SPG
|
||||
1 Prismatic Ending|SPG
|
||||
1 Dismember|SPG
|
||||
1 Persist|SPG
|
||||
1 Expressive Iteration|SPG
|
||||
1 Solitude|SPG
|
||||
1 Subtlety|SPG
|
||||
1 Grief|SPG
|
||||
1 Fury|SPG
|
||||
1 Endurance|SPG
|
||||
|
||||
[tokens]
|
||||
b_0_0_phyrexian_germ
|
||||
b_0_0_zombie_army
|
||||
|
||||
Reference in New Issue
Block a user