mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 03:08:02 +00:00
Fix getTotalPreventionShieldAmount (#3654)
* Fix scripts * Fix damage prevention display * Optimize attachment tracking for netplay * Phasing fix * Fix NPE * Tweak logic order * Clean up * Fix scripts * Clean up * Fix FailedToTarget --------- Co-authored-by: TRT <>
This commit is contained in:
@@ -398,10 +398,8 @@ public class ComputerUtilCost {
|
||||
return false;
|
||||
}
|
||||
for (final CostPart part : cost.getCostParts()) {
|
||||
if (part instanceof CostSacrifice) {
|
||||
if ("CARDNAME".equals(part.getType())) {
|
||||
return true;
|
||||
}
|
||||
if (part instanceof CostSacrifice && part.payCostFromSource()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -85,7 +85,7 @@ public class DamagePreventAi extends SpellAbilityAi {
|
||||
// check stack for something on the stack will kill anything i control
|
||||
final List<GameObject> objects = ComputerUtil.predictThreatenedObjects(sa.getActivatingPlayer(), sa);
|
||||
|
||||
if (objects.contains(ai)) {
|
||||
if (objects.contains(ai) && sa.canTarget(ai)) {
|
||||
tcs.add(ai);
|
||||
chance = true;
|
||||
}
|
||||
|
||||
@@ -216,6 +216,7 @@ public class EffectAi extends SpellAbilityAi {
|
||||
} else if (logic.equals("Fight")) {
|
||||
return FightAi.canFightAi(ai, sa, 0, 0);
|
||||
} else if (logic.equals("Pump")) {
|
||||
sa.resetTargets();
|
||||
List<Card> options = CardUtil.getValidCardsToTarget(sa);
|
||||
options = CardLists.filterControlledBy(options, ai);
|
||||
if (sa.getPayCosts().hasTapCost()) {
|
||||
|
||||
@@ -89,7 +89,7 @@ public class ManaEffectAi extends SpellAbilityAi {
|
||||
if (logic.startsWith("ManaRitual")) {
|
||||
return ph.is(PhaseType.MAIN2, ai) || ph.is(PhaseType.MAIN1, ai);
|
||||
} else if ("AtOppEOT".equals(logic)) {
|
||||
return !ai.getManaPool().hasBurn() && ph.is(PhaseType.END_OF_TURN) && ph.getNextTurn() == ai;
|
||||
return (!ai.getManaPool().hasBurn() || !ai.canLoseLife() || ai.cantLoseForZeroOrLessLife()) && ph.is(PhaseType.END_OF_TURN) && ph.getNextTurn() == ai;
|
||||
}
|
||||
return super.checkPhaseRestrictions(ai, sa, ph, logic);
|
||||
}
|
||||
@@ -261,7 +261,8 @@ public class ManaEffectAi extends SpellAbilityAi {
|
||||
}
|
||||
|
||||
private boolean improvesPosition(Player ai, SpellAbility sa) {
|
||||
boolean activateForTrigger = Iterables.any(Iterables.filter(sa.getHostCard().getTriggers(), CardTraitPredicates.hasParam("AILogic", "ActivateOnce")),
|
||||
boolean activateForTrigger = (!ai.getManaPool().hasBurn() || !ai.canLoseLife() || ai.cantLoseForZeroOrLessLife()) &&
|
||||
Iterables.any(Iterables.filter(sa.getHostCard().getTriggers(), CardTraitPredicates.hasParam("AILogic", "ActivateOnce")),
|
||||
t -> sa.getHostCard().getAbilityActivatedThisTurn(t.getOverridingAbility()) == 0);
|
||||
|
||||
PhaseHandler ph = ai.getGame().getPhaseHandler();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package forge.game;
|
||||
|
||||
import forge.game.card.CardCollectionView;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
import forge.game.card.CardView;
|
||||
import forge.trackable.TrackableCollection;
|
||||
import forge.trackable.TrackableObject;
|
||||
@@ -45,35 +46,34 @@ public abstract class GameEntityView extends TrackableObject {
|
||||
public int getPreventNextDamage() {
|
||||
return get(TrackableProperty.PreventNextDamage);
|
||||
}
|
||||
protected void updatePreventNextDamage(GameEntity e) {
|
||||
public void updatePreventNextDamage(GameEntity e) {
|
||||
set(TrackableProperty.PreventNextDamage, e.getPreventNextDamageTotalShields());
|
||||
}
|
||||
|
||||
public Iterable<CardView> getAttachedCards() {
|
||||
return get(TrackableProperty.AttachedCards);
|
||||
if (hasAnyCardAttachments()) {
|
||||
Iterable<CardView> active = Iterables.filter(get(TrackableProperty.AttachedCards), c -> !c.isPhasedOut());
|
||||
if (!Iterables.isEmpty(active)) {
|
||||
return active;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public boolean hasCardAttachments() {
|
||||
return getAttachedCards() != null;
|
||||
}
|
||||
public Iterable<CardView> getAllAttachedCards() {
|
||||
return get(TrackableProperty.AllAttachedCards);
|
||||
return get(TrackableProperty.AttachedCards);
|
||||
}
|
||||
public boolean hasAnyCardAttachments() {
|
||||
return getAllAttachedCards() != null;
|
||||
}
|
||||
|
||||
protected void updateAttachedCards(GameEntity e) {
|
||||
if (e.hasCardAttachments()) {
|
||||
set(TrackableProperty.AttachedCards, CardView.getCollection(e.getAttachedCards()));
|
||||
}
|
||||
else {
|
||||
set(TrackableProperty.AttachedCards, null);
|
||||
}
|
||||
CardCollectionView all = e.getAllAttachedCards();
|
||||
if (all.isEmpty()) {
|
||||
set(TrackableProperty.AllAttachedCards, null);
|
||||
if (!e.getAllAttachedCards().isEmpty()) {
|
||||
set(TrackableProperty.AttachedCards, CardView.getCollection(e.getAllAttachedCards()));
|
||||
} else {
|
||||
set(TrackableProperty.AllAttachedCards, CardView.getCollection(all));
|
||||
set(TrackableProperty.AttachedCards, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1999,13 +1999,6 @@ public class AbilityUtils {
|
||||
return doXMath(calculateAmount(c, sq[c.isOptionalCostPaid(OptionalCost.Generic) ? 1 : 2], ctb), expr, c, ctb);
|
||||
}
|
||||
|
||||
if (sq[0].equals("TotalDamageDoneByThisTurn")) {
|
||||
return doXMath(c.getTotalDamageDoneBy(), expr, c, ctb);
|
||||
}
|
||||
if (sq[0].equals("TotalDamageReceivedThisTurn")) {
|
||||
return doXMath(c.getAssignedDamage(), expr, c, ctb);
|
||||
}
|
||||
|
||||
if (sq[0].contains("CardPower")) {
|
||||
return doXMath(c.getNetPower(), expr, c, ctb);
|
||||
}
|
||||
@@ -2335,6 +2328,13 @@ public class AbilityUtils {
|
||||
return doXMath(player.getOpponentsTotalPoisonCounters(), expr, c, ctb);
|
||||
}
|
||||
|
||||
if (sq[0].equals("TotalDamageDoneByThisTurn")) {
|
||||
return doXMath(c.getTotalDamageDoneBy(), expr, c, ctb);
|
||||
}
|
||||
if (sq[0].equals("TotalDamageReceivedThisTurn")) {
|
||||
return doXMath(c.getAssignedDamage(), expr, c, ctb);
|
||||
}
|
||||
|
||||
if (sq[0].equals("MaxOppDamageThisTurn")) {
|
||||
return doXMath(player.getMaxOpponentAssignedDamage(), expr, c, ctb);
|
||||
}
|
||||
@@ -3493,6 +3493,7 @@ public class AbilityUtils {
|
||||
if (value.equals("RingTemptedYou")) {
|
||||
return doXMath(player.getNumRingTemptedYou(), m, source, ctb);
|
||||
}
|
||||
|
||||
if (value.startsWith("DungeonCompletedNamed")) {
|
||||
String [] full = value.split("_");
|
||||
String name = full[1];
|
||||
|
||||
@@ -4,12 +4,13 @@ import java.util.List;
|
||||
|
||||
import forge.GameCommand;
|
||||
import forge.game.Game;
|
||||
import forge.game.GameObject;
|
||||
import forge.game.GameEntity;
|
||||
import forge.game.ability.AbilityFactory;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.SpellAbilityEffect;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.event.GameEventPlayerStatsChanged;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.replacement.ReplacementEffect;
|
||||
import forge.game.replacement.ReplacementHandler;
|
||||
@@ -20,7 +21,7 @@ import forge.game.zone.ZoneType;
|
||||
import forge.util.TextUtil;
|
||||
|
||||
public abstract class DamagePreventEffectBase extends SpellAbilityEffect {
|
||||
public static void addPreventNextDamage(SpellAbility sa, GameObject o, int numDam) {
|
||||
public static void addPreventNextDamage(SpellAbility sa, GameEntity o, int numDam) {
|
||||
final Card hostCard = sa.getHostCard();
|
||||
final Game game = hostCard.getGame();
|
||||
final Player player = hostCard.getController();
|
||||
@@ -40,9 +41,9 @@ public abstract class DamagePreventEffectBase extends SpellAbilityEffect {
|
||||
if (sa.hasParam("PreventionSubAbility")) {
|
||||
String subAbString = sa.getSVar(sa.getParam("PreventionSubAbility"));
|
||||
if (sa.hasParam("ShieldEffectTarget")) {
|
||||
List<GameObject> effTgts = AbilityUtils.getDefinedObjects(hostCard, sa.getParam("ShieldEffectTarget"), sa);
|
||||
List<GameEntity> effTgts = AbilityUtils.getDefinedEntities(hostCard, sa.getParam("ShieldEffectTarget"), sa);
|
||||
String effTgtString = "";
|
||||
for (final GameObject effTgt : effTgts) {
|
||||
for (final GameEntity effTgt : effTgts) {
|
||||
if (effTgt instanceof Card) {
|
||||
effTgtString = "CardUID_" + String.valueOf(((Card) effTgt).getId());
|
||||
} else if (effTgt instanceof Player) {
|
||||
@@ -70,12 +71,21 @@ public abstract class DamagePreventEffectBase extends SpellAbilityEffect {
|
||||
eff.updateStateForView();
|
||||
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
|
||||
|
||||
o.getView().updatePreventNextDamage(o);
|
||||
if (o instanceof Player) {
|
||||
game.fireEvent(new GameEventPlayerStatsChanged((Player) o, false));
|
||||
}
|
||||
|
||||
game.getEndOfTurn().addUntil(new GameCommand() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
game.getAction().exile(eff, null);
|
||||
o.getView().updatePreventNextDamage(o);
|
||||
if (o instanceof Player) {
|
||||
game.fireEvent(new GameEventPlayerStatsChanged((Player) o, false));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -5636,7 +5636,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
/**
|
||||
* Gets the total damage done by card this turn (after prevention and redirects).
|
||||
*
|
||||
* @return the damage done to player p this turn
|
||||
* @return the damage done by the card this turn
|
||||
*/
|
||||
public final int getTotalDamageDoneBy() {
|
||||
return getDamageHistory().getDamageDoneThisTurn(null, false, null, null, this, getController(), null);
|
||||
|
||||
@@ -19,6 +19,7 @@ import forge.game.Game;
|
||||
import forge.game.GameEntity;
|
||||
import forge.game.GameObjectPredicates;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.event.GameEventPlayerStatsChanged;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerCollection;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
@@ -48,6 +49,11 @@ public class CardDamageMap extends ForwardingTable<Card, GameEntity, Integer> {
|
||||
runParams.put(AbilityKey.IsCombatDamage, isCombat);
|
||||
|
||||
ge.getGame().getTriggerHandler().runTrigger(TriggerType.DamagePreventedOnce, runParams, false);
|
||||
|
||||
ge.getView().updatePreventNextDamage(ge);
|
||||
if (ge instanceof Player) {
|
||||
ge.getGame().fireEvent(new GameEventPlayerStatsChanged((Player) ge, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,7 +362,6 @@ public class AttackConstraints {
|
||||
MapToAmount<GameEntity> sortedPlayerReqs = new LinkedHashMapToAmount<>();
|
||||
sortedPlayerReqs.addAll(Iterables.concat(playerReqs));
|
||||
while (!sortedPlayerReqs.isEmpty()) {
|
||||
sortedPlayerReqs.keySet().removeAll(excludedDefenders);
|
||||
Pair<GameEntity, Integer> playerReq = MapToAmountUtil.max(sortedPlayerReqs);
|
||||
// find best attack to also fulfill the additional requirements
|
||||
Attack bestMatch = Iterables.getLast(Iterables.filter(result, att -> !usedAttackers.contains(att.attacker) && att.defender.equals(playerReq.getLeft())), null);
|
||||
@@ -376,6 +375,7 @@ public class AttackConstraints {
|
||||
} else {
|
||||
excludedDefenders.add(playerReq.getLeft());
|
||||
}
|
||||
sortedPlayerReqs.keySet().removeAll(excludedDefenders);
|
||||
}
|
||||
if (!usedAttackers.isEmpty()) {
|
||||
// order could have changed
|
||||
|
||||
@@ -42,6 +42,7 @@ import forge.game.keyword.KeywordInterface;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerController.BinaryChoiceType;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.staticability.StaticAbilityCantPhaseOut;
|
||||
import forge.game.zone.ZoneType;
|
||||
|
||||
/**
|
||||
@@ -266,14 +267,14 @@ public class Untap extends Phase {
|
||||
// If c is attached to something, it will phase out on its own, and try
|
||||
// to attach back to that thing when it comes back
|
||||
for (final Card c : list) {
|
||||
if (c.isPhasedOut()) {
|
||||
if (c.isPhasedOut() && c.isDirectlyPhasedOut()) {
|
||||
c.phase(true);
|
||||
} else if (c.hasKeyword(Keyword.PHASING)) {
|
||||
// CR 702.26h If an object would simultaneously phase out directly
|
||||
// and indirectly, it just phases out indirectly.
|
||||
if (c.isAttachment()) {
|
||||
final Card ent = c.getAttachedTo();
|
||||
if (ent != null && list.contains(ent)) {
|
||||
if (ent != null && list.contains(ent) && !StaticAbilityCantPhaseOut.cantPhaseOut(ent)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,7 +145,6 @@ public abstract class ReplacementEffect extends TriggerReplacementBase {
|
||||
public boolean requirementsCheck(Game game) {
|
||||
return this.requirementsCheck(game, this.getMapParams());
|
||||
}
|
||||
|
||||
public boolean requirementsCheck(Game game, Map<String,String> params) {
|
||||
if (this.isSuppressed()) {
|
||||
return false; // Effect removed by effect
|
||||
|
||||
@@ -911,7 +911,8 @@ public class ReplacementHandler {
|
||||
&& re.hasParam("PreventionEffect")
|
||||
&& re.zonesCheck(game.getZoneOf(c))
|
||||
&& re.getOverridingAbility() != null
|
||||
&& re.getOverridingAbility().getApi() == ApiType.ReplaceDamage) {
|
||||
&& re.getOverridingAbility().getApi() == ApiType.ReplaceDamage
|
||||
&& re.matchesValidParam("ValidTarget", o)) {
|
||||
list.add(re);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ public enum TrackableProperty {
|
||||
Text(TrackableTypes.StringType),
|
||||
PreventNextDamage(TrackableTypes.IntegerType),
|
||||
AttachedCards(TrackableTypes.CardViewCollectionType),
|
||||
AllAttachedCards(TrackableTypes.CardViewCollectionType),
|
||||
Counters(TrackableTypes.CounterMapType),
|
||||
CurrentPlane(TrackableTypes.StringType),
|
||||
PlanarPlayer(TrackableTypes.PlayerViewType),
|
||||
|
||||
@@ -595,8 +595,7 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen
|
||||
Iterable<CardView> cards = model.getCards(zone);
|
||||
if (cards != null) {
|
||||
modelCopy = Lists.newArrayList(cards);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
modelCopy = Lists.newArrayList();
|
||||
}
|
||||
}
|
||||
@@ -648,17 +647,17 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen
|
||||
doLayout();
|
||||
}
|
||||
|
||||
invalidate(); //pfps do the extra invalidate before any scrolling
|
||||
invalidate(); //pfps do the extra invalidate before any scrolling
|
||||
if (!newPanels.isEmpty()) {
|
||||
int i = newPanels.size();
|
||||
int i = newPanels.size();
|
||||
for (final CardPanel toPanel : newPanels) {
|
||||
if ( --i == 0 ) { // only scroll to last panel to be added
|
||||
scrollRectToVisible(new Rectangle(toPanel.getCardX(), toPanel.getCardY(), toPanel.getCardWidth(), toPanel.getCardHeight()));
|
||||
}
|
||||
if ( --i == 0 ) { // only scroll to last panel to be added
|
||||
scrollRectToVisible(new Rectangle(toPanel.getCardX(), toPanel.getCardY(), toPanel.getCardWidth(), toPanel.getCardHeight()));
|
||||
}
|
||||
Animation.moveCard(toPanel);
|
||||
}
|
||||
}
|
||||
repaint();
|
||||
}
|
||||
repaint();
|
||||
}
|
||||
|
||||
public boolean updateCard(final CardView card, boolean fromRefresh) {
|
||||
|
||||
@@ -2,5 +2,6 @@ Name:Break of Day
|
||||
ManaCost:1 W
|
||||
Types:Instant
|
||||
A:SP$ PumpAll | Cost$ 1 W | ValidCards$ Creature.YouCtrl | NumAtt$ +1 | NumDef$ +1 | SubAbility$ FatefulHourPump | SpellDescription$ Creatures you control get +1/+1 until end of turn.
|
||||
SVar:FatefulHourPump:DB$ PumpAll | ValidCards$ Creature.YouCtrl | KW$ Indestructible | FatefulHour$ True | SpellDescription$ Fateful hour — If you have 5 or less life, those creatures gain indestructible until end of turn.
|
||||
SVar:FatefulHourPump:DB$ PumpAll | ValidCards$ Creature.YouCtrl | KW$ Indestructible | ConditionCheckSVar$ FatefulHour | ConditionSVarCompare$ LE5 | SpellDescription$ Fateful hour — If you have 5 or less life, those creatures gain indestructible until end of turn.
|
||||
SVar:FatefulHour:Count$YourLifeTotal
|
||||
Oracle:Creatures you control get +1/+1 until end of turn.\nFateful hour — If you have 5 or less life, those creatures gain indestructible until end of turn. (Damage and effects that say "destroy" don't destroy them.)
|
||||
|
||||
@@ -2,7 +2,7 @@ Name:Ogre Slumlord
|
||||
ManaCost:3 B B
|
||||
Types:Creature Ogre Rogue
|
||||
PT:3/3
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Creature.nonToken+Other | TriggerZones$ Battlefield | Execute$ TrigToken | TriggerDescription$ Whenever another nontoken creature dies, you may create a 1/1 black Rat creature token.
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Creature.nonToken+Other | OptionalDecider$ You | TriggerZones$ Battlefield | Execute$ TrigToken | TriggerDescription$ Whenever another nontoken creature dies, you may create a 1/1 black Rat creature token.
|
||||
SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ b_1_1_rat | TokenOwner$ You
|
||||
S:Mode$ Continuous | Affected$ Creature.Rat+YouCtrl | AddKeyword$ Deathtouch | Description$ Rats you control have deathtouch.
|
||||
DeckHas:Ability$Token
|
||||
|
||||
@@ -4,7 +4,7 @@ Types:Legendary Creature Spirit Naga
|
||||
PT:0/0
|
||||
K:etbCounter:P1P1:X
|
||||
SVar:X:Count$xPaid
|
||||
T:Mode$ CounterAddedOnce | ValidCard$ Creature.Other+inZoneBattlefield+Colorless | OptionalDecider$ You | TriggerZones$ Battlefield | CounterType$ P1P1 | Execute$ TrigPutCounter | TriggerDescription$ Whenever you put one or more +1/+1 counters on another colorless creature, you may put a +1/+1 counter on NICKNAME.
|
||||
T:Mode$ CounterAddedOnce | ValidCard$ Creature.Other+inZoneBattlefield+Colorless | ValidPlayer$ You | OptionalDecider$ You | TriggerZones$ Battlefield | CounterType$ P1P1 | Execute$ TrigPutCounter | TriggerDescription$ Whenever you put one or more +1/+1 counters on another colorless creature, you may put a +1/+1 counter on NICKNAME.
|
||||
SVar:TrigPutCounter:DB$ PutCounter | CounterType$ P1P1 | CounterNum$ 1
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigManifest | TriggerDescription$ When NICKNAME dies, manifest a number of cards from the top of your library equal to the number of counters on it.
|
||||
SVar:TrigManifest:DB$ Manifest | Amount$ Y | Defined$ TopOfLibrary
|
||||
|
||||
@@ -4,7 +4,7 @@ Types:Enchantment Aura
|
||||
K:Flash
|
||||
K:Enchant creature you control
|
||||
A:SP$ Attach | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature you control | AILogic$ Pump
|
||||
T:Mode$ ChangesZone | ValidCard$ Creature.EnchantedBy,Creature.modified+NotEnchantedBy | Origin$ Battlefield | Destination$ Graveyard | Execute$ TrigToken | TriggerDescription$ Whenever enchanted creature or another modified creature you control dies, create X 1/1 colorless Spirit creature tokens, where X is that creature's power. (Equipment, Auras you control, and counters are modifications.)
|
||||
T:Mode$ ChangesZone | ValidCard$ Creature.EnchantedBy,Creature.YouCtrl+modified+NotEnchantedBy | Origin$ Battlefield | Destination$ Graveyard | Execute$ TrigToken | TriggerDescription$ Whenever enchanted creature or another modified creature you control dies, create X 1/1 colorless Spirit creature tokens, where X is that creature's power. (Equipment, Auras you control, and counters are modifications.)
|
||||
SVar:TrigToken:DB$ Token | TokenScript$ c_1_1_spirit | TokenAmount$ X
|
||||
SVar:X:TriggeredCard$CardPower
|
||||
DeckHas:Ability$Token & Type$Spirit
|
||||
|
||||
@@ -3,5 +3,5 @@ ManaCost:2 R
|
||||
Types:Creature Goblin Rogue
|
||||
PT:3/2
|
||||
T:Mode$ TapsForMana | ValidCard$ Artifact | Activator$ Opponent | TriggerZones$ Battlefield | Execute$ TrigControl | TriggerDescription$ Whenever an opponent taps an artifact for mana, gain control of that artifact until the end of your next turn.
|
||||
SVar:TrigControl:DB$ GainControl | Defined$ TriggeredCard | LoseControl$ UntilTheEndOfYourNextTurn
|
||||
SVar:TrigControl:DB$ GainControl | Defined$ TriggeredCardLKICopy | LoseControl$ UntilTheEndOfYourNextTurn
|
||||
Oracle:Whenever an opponent taps an artifact for mana, gain control of that artifact until the end of your next turn.
|
||||
|
||||
@@ -2,7 +2,7 @@ Name:Unexpected Allies
|
||||
ManaCost:1 R
|
||||
Types:Sorcery
|
||||
A:SP$ Pump | ValidTgts$ Creature.YouCtrl+nonToken | TgtPrompt$ Select target nontoken creature you control | KW$ Double team | NumAtt$ 2 | SubAbility$ TrigEffect | SpellDescription$ Target nontoken creature you control gets +2/+0 and gains double team until end of turn. It also gains first strike until end of turn if it has the same name as another creature you control or a creature card in your graveyard.
|
||||
SVar:TrigEffect:DB$ Pump | ConditionCheckSVar$ X | Defined$ Targeted | KW$ First strike
|
||||
SVar:TrigEffect:DB$ Pump | ConditionCheckSVar$ X | Defined$ Targeted | KW$ First Strike
|
||||
SVar:X:Count$Valid Creature.NotDefinedTargeted+YouCtrl+sharesNameWith Targeted/Plus.Y
|
||||
SVar:Y:Count$ValidGraveyard Creature.YouOwn+sharesNameWith Targeted
|
||||
DeckHas:Keyword$Double Team|First Strike
|
||||
|
||||
@@ -69,7 +69,6 @@ public class InputAttack extends InputSyncronizedBase {
|
||||
|
||||
@Override
|
||||
public final void showMessage() {
|
||||
// TODO still seems to have some issues with multiple planeswalkers
|
||||
setCurrentDefender(defenders.getFirst());
|
||||
|
||||
if (currentDefender == null) {
|
||||
@@ -295,7 +294,9 @@ public class InputAttack extends InputSyncronizedBase {
|
||||
getController().getGui().setHighlighted(PlayerView.get((Player) ge), ge == def);
|
||||
}
|
||||
}
|
||||
potentialBanding = isBandingPossible();
|
||||
if (def != null) {
|
||||
potentialBanding = isBandingPossible();
|
||||
}
|
||||
|
||||
updateMessage();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user