mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 20:28:00 +00:00
Player keyword rework
This commit is contained in:
@@ -228,7 +228,7 @@ public class GameCopier {
|
|||||||
CardFactory.copyCopiableCharacteristics(c, result);
|
CardFactory.copyCopiableCharacteristics(c, result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
if (USE_FROM_PAPER_CARD && !c.isEmblem()) {
|
if (USE_FROM_PAPER_CARD && !c.isEmblem() && c.getPaperCard() != null) {
|
||||||
Card newCard = Card.fromPaperCard(c.getPaperCard(), newOwner);
|
Card newCard = Card.fromPaperCard(c.getPaperCard(), newOwner);
|
||||||
newCard.setCommander(c.isCommander());
|
newCard.setCommander(c.isCommander());
|
||||||
return newCard;
|
return newCard;
|
||||||
|
|||||||
@@ -120,7 +120,10 @@ public class PumpEffect extends SpellAbilityEffect {
|
|||||||
&& !(host.isInPlay() || host.isInZone(ZoneType.Stack))) {
|
&& !(host.isInPlay() || host.isInZone(ZoneType.Stack))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
p.addChangedKeywords(keywords, ImmutableList.of(), timestamp);
|
|
||||||
|
if (!keywords.isEmpty()) {
|
||||||
|
p.addChangedKeywords(keywords, ImmutableList.of(), timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
if (!sa.hasParam("Permanent")) {
|
if (!sa.hasParam("Permanent")) {
|
||||||
// If not Permanent, remove Pumped at EOT
|
// If not Permanent, remove Pumped at EOT
|
||||||
@@ -129,12 +132,7 @@ public class PumpEffect extends SpellAbilityEffect {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
p.removeChangedKeywords(timestamp);
|
||||||
if (keywords.size() > 0) {
|
|
||||||
for (int i = 0; i < keywords.size(); i++) {
|
|
||||||
p.removeKeyword(keywords.get(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
addUntilCommand(sa, untilEOT);
|
addUntilCommand(sa, untilEOT);
|
||||||
|
|||||||
@@ -5618,34 +5618,7 @@ public class Card extends GameEntity implements Comparable<Card> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final Card source = sa.getHostCard();
|
final Card source = sa.getHostCard();
|
||||||
final MutableBoolean result = new MutableBoolean(true);
|
|
||||||
visitKeywords(currentState, new Visitor<KeywordInterface>() {
|
|
||||||
@Override
|
|
||||||
public boolean visit(KeywordInterface kw) {
|
|
||||||
switch (kw.getOriginal()) {
|
|
||||||
case "Shroud":
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
sb.append("Can target CardUID_").append(getId());
|
|
||||||
sb.append(" with spells and abilities as though it didn't have shroud.");
|
|
||||||
if (sa.getActivatingPlayer() == null) {
|
|
||||||
System.err.println("Unexpected behavior: SA activator was null when trying to determine if the activating player could target a card with Shroud. SA host card = " + source + ", SA = " + sa);
|
|
||||||
result.setFalse(); // FIXME: maybe this should check by SA host card controller at this point instead?
|
|
||||||
} else if (!sa.getActivatingPlayer().hasKeyword(sb.toString())) {
|
|
||||||
result.setFalse();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "CARDNAME can't be the target of spells.":
|
|
||||||
if (sa.isSpell()) {
|
|
||||||
result.setFalse();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return result.isTrue();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (result.isFalse()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (sa.isSpell()) {
|
if (sa.isSpell()) {
|
||||||
for(KeywordInterface inst : source.getKeywords()) {
|
for(KeywordInterface inst : source.getKeywords()) {
|
||||||
String kw = inst.getOriginal();
|
String kw = inst.getOriginal();
|
||||||
|
|||||||
@@ -4501,7 +4501,9 @@ public class CardFactoryUtil {
|
|||||||
effect = "Mode$ CantTarget | Hexproof$ True | ValidCard$ Card.Self | Secondary$ True"
|
effect = "Mode$ CantTarget | Hexproof$ True | ValidCard$ Card.Self | Secondary$ True"
|
||||||
+ sbValid.toString() + " | Activator$ Opponent | Description$ "
|
+ sbValid.toString() + " | Activator$ Opponent | Description$ "
|
||||||
+ sbDesc.toString() + " (" + inst.getReminderText() + ")";
|
+ sbDesc.toString() + " (" + inst.getReminderText() + ")";
|
||||||
|
} else if (keyword.equals("Shroud")) {
|
||||||
|
effect = "Mode$ CantTarget | Shroud$ True | ValidCard$ Card.Self | Secondary$ True"
|
||||||
|
+ " | Description$ Shroud (" + inst.getReminderText() + ")";
|
||||||
} else if (keyword.startsWith("Strive")) {
|
} else if (keyword.startsWith("Strive")) {
|
||||||
final String[] k = keyword.split(":");
|
final String[] k = keyword.split(":");
|
||||||
final String manacost = k[1];
|
final String manacost = k[1];
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import com.google.common.collect.Lists;
|
|||||||
|
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.card.CardFactoryUtil;
|
import forge.game.card.CardFactoryUtil;
|
||||||
|
import forge.game.player.Player;
|
||||||
|
import forge.game.player.PlayerFactoryUtil;
|
||||||
import forge.game.replacement.ReplacementEffect;
|
import forge.game.replacement.ReplacementEffect;
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
import forge.game.staticability.StaticAbility;
|
import forge.game.staticability.StaticAbility;
|
||||||
@@ -125,6 +127,53 @@ public abstract class KeywordInstance<T extends KeywordInstance<?>> implements K
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see forge.game.keyword.KeywordInterface#createTraits(forge.game.player.Player)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void createTraits(Player player) {
|
||||||
|
createTraits(player, false);
|
||||||
|
}
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see forge.game.keyword.KeywordInterface#createTraits(forge.game.player.Player, boolean)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void createTraits(Player player, boolean clear) {
|
||||||
|
if (clear) {
|
||||||
|
triggers.clear();
|
||||||
|
replacements.clear();
|
||||||
|
abilities.clear();
|
||||||
|
staticAbilities.clear();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
String msg = "KeywordInstance:createTraits: make Traits for Keyword";
|
||||||
|
Sentry.getContext().recordBreadcrumb(
|
||||||
|
new BreadcrumbBuilder().setMessage(msg)
|
||||||
|
.withData("Player", player.getName()).withData("Keyword", this.original).build()
|
||||||
|
);
|
||||||
|
|
||||||
|
// add Extra for debugging
|
||||||
|
Sentry.getContext().addExtra("Player", player);
|
||||||
|
Sentry.getContext().addExtra("Keyword", this.original);
|
||||||
|
|
||||||
|
PlayerFactoryUtil.addTriggerAbility(this, player);
|
||||||
|
PlayerFactoryUtil.addReplacementEffect(this, player);
|
||||||
|
PlayerFactoryUtil.addSpellAbility(this, player);
|
||||||
|
PlayerFactoryUtil.addStaticAbility(this, player);
|
||||||
|
} catch (Exception e) {
|
||||||
|
String msg = "KeywordInstance:createTraits: failed Traits for Keyword";
|
||||||
|
Sentry.getContext().recordBreadcrumb(
|
||||||
|
new BreadcrumbBuilder().setMessage(msg)
|
||||||
|
.withData("Player", player.getName()).withData("Keyword", this.original).build()
|
||||||
|
);
|
||||||
|
//rethrow
|
||||||
|
throw new RuntimeException("Error in Keyword " + this.original + " for player " + player.getName(), e);
|
||||||
|
} finally {
|
||||||
|
// remove added extra
|
||||||
|
Sentry.getContext().removeExtra("Player");
|
||||||
|
Sentry.getContext().removeExtra("Keyword");
|
||||||
|
}
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
* @see forge.game.keyword.KeywordInterface#addTrigger(forge.game.trigger.Trigger)
|
* @see forge.game.keyword.KeywordInterface#addTrigger(forge.game.trigger.Trigger)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package forge.game.keyword;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
|
import forge.game.player.Player;
|
||||||
import forge.game.replacement.ReplacementEffect;
|
import forge.game.replacement.ReplacementEffect;
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
import forge.game.staticability.StaticAbility;
|
import forge.game.staticability.StaticAbility;
|
||||||
@@ -24,6 +25,9 @@ public interface KeywordInterface extends Cloneable {
|
|||||||
void createTraits(final Card host, final boolean intrinsic);
|
void createTraits(final Card host, final boolean intrinsic);
|
||||||
void createTraits(final Card host, final boolean intrinsic, final boolean clear);
|
void createTraits(final Card host, final boolean intrinsic, final boolean clear);
|
||||||
|
|
||||||
|
void createTraits(final Player player);
|
||||||
|
void createTraits(final Player player, final boolean clear);
|
||||||
|
|
||||||
void addTrigger(final Trigger trg);
|
void addTrigger(final Trigger trg);
|
||||||
|
|
||||||
void addReplacement(final ReplacementEffect trg);
|
void addReplacement(final ReplacementEffect trg);
|
||||||
|
|||||||
@@ -23,6 +23,11 @@ import java.util.List;
|
|||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
|
import forge.game.player.Player;
|
||||||
|
import forge.game.replacement.ReplacementEffect;
|
||||||
|
import forge.game.spellability.SpellAbility;
|
||||||
|
import forge.game.staticability.StaticAbility;
|
||||||
|
import forge.game.trigger.Trigger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
@@ -132,6 +137,12 @@ public class KeywordsChange implements Cloneable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final void addKeywordsToPlayer(final Player player) {
|
||||||
|
for (KeywordInterface inst : keywords.getValues()) {
|
||||||
|
inst.createTraits(player, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public final boolean removeKeywordfromAdd(final String keyword) {
|
public final boolean removeKeywordfromAdd(final String keyword) {
|
||||||
return keywords.remove(keyword);
|
return keywords.remove(keyword);
|
||||||
}
|
}
|
||||||
@@ -201,6 +212,47 @@ public class KeywordsChange implements Cloneable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the triggers
|
||||||
|
*/
|
||||||
|
public Collection<Trigger> getTriggers() {
|
||||||
|
List<Trigger> result = Lists.newArrayList();
|
||||||
|
for (KeywordInterface k : this.keywords.getValues()) {
|
||||||
|
result.addAll(k.getTriggers());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @return the replacements
|
||||||
|
*/
|
||||||
|
public Collection<ReplacementEffect> getReplacements() {
|
||||||
|
List<ReplacementEffect> result = Lists.newArrayList();
|
||||||
|
for (KeywordInterface k : this.keywords.getValues()) {
|
||||||
|
result.addAll(k.getReplacements());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @return the abilities
|
||||||
|
*/
|
||||||
|
public Collection<SpellAbility> getAbilities() {
|
||||||
|
List<SpellAbility> result = Lists.newArrayList();
|
||||||
|
for (KeywordInterface k : this.keywords.getValues()) {
|
||||||
|
result.addAll(k.getAbilities());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @return the staticAbilities
|
||||||
|
*/
|
||||||
|
public Collection<StaticAbility> getStaticAbilities() {
|
||||||
|
List<StaticAbility> result = Lists.newArrayList();
|
||||||
|
for (KeywordInterface k : this.keywords.getValues()) {
|
||||||
|
result.addAll(k.getStaticAbilities());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see java.lang.Object#toString()
|
* @see java.lang.Object#toString()
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ package forge.game.player;
|
|||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
import com.google.common.base.Predicates;
|
import com.google.common.base.Predicates;
|
||||||
import com.google.common.collect.*;
|
import com.google.common.collect.*;
|
||||||
|
|
||||||
|
import forge.ImageKeys;
|
||||||
import forge.LobbyPlayer;
|
import forge.LobbyPlayer;
|
||||||
import forge.card.MagicColor;
|
import forge.card.MagicColor;
|
||||||
import forge.game.*;
|
import forge.game.*;
|
||||||
@@ -41,7 +43,6 @@ import forge.game.phase.PhaseType;
|
|||||||
import forge.game.replacement.ReplacementHandler;
|
import forge.game.replacement.ReplacementHandler;
|
||||||
import forge.game.replacement.ReplacementResult;
|
import forge.game.replacement.ReplacementResult;
|
||||||
import forge.game.replacement.ReplacementType;
|
import forge.game.replacement.ReplacementType;
|
||||||
import forge.game.spellability.AbilityActivated;
|
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
import forge.game.staticability.StaticAbility;
|
import forge.game.staticability.StaticAbility;
|
||||||
import forge.game.trigger.Trigger;
|
import forge.game.trigger.Trigger;
|
||||||
@@ -155,6 +156,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
|
|
||||||
private Card monarchEffect = null;
|
private Card monarchEffect = null;
|
||||||
private Card blessingEffect = null;
|
private Card blessingEffect = null;
|
||||||
|
private Card keywordEffect = null;
|
||||||
|
|
||||||
private final AchievementTracker achievementTracker = new AchievementTracker();
|
private final AchievementTracker achievementTracker = new AchievementTracker();
|
||||||
private final PlayerView view;
|
private final PlayerView view;
|
||||||
@@ -1025,23 +1027,25 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
|
|
||||||
public final void addChangedKeywords(final List<String> addKeywords, final List<String> removeKeywords, final Long timestamp) {
|
public final void addChangedKeywords(final List<String> addKeywords, final List<String> removeKeywords, final Long timestamp) {
|
||||||
// if the key already exists - merge entries
|
// if the key already exists - merge entries
|
||||||
|
KeywordsChange cks = null;
|
||||||
if (changedKeywords.containsKey(timestamp)) {
|
if (changedKeywords.containsKey(timestamp)) {
|
||||||
final KeywordsChange cks = changedKeywords.get(timestamp);
|
getKeywordCard().removeChangedCardTraits(timestamp);
|
||||||
|
|
||||||
changedKeywords.put(timestamp, cks.merge(addKeywords, removeKeywords,
|
cks = changedKeywords.get(timestamp).merge(addKeywords, removeKeywords, false, false);
|
||||||
cks.isRemoveAllKeywords(), cks.isRemoveIntrinsicKeywords()));
|
} else {
|
||||||
updateKeywords();
|
cks = new KeywordsChange(addKeywords, removeKeywords, false, false);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
cks.addKeywordsToPlayer(this);
|
||||||
changedKeywords.put(timestamp, new KeywordsChange(addKeywords, removeKeywords, false, false));
|
getKeywordCard().addChangedCardTraits(cks.getAbilities(), null, cks.getTriggers(), cks.getReplacements(), cks.getStaticAbilities(), false, false, false, timestamp);
|
||||||
|
changedKeywords.put(timestamp, cks);
|
||||||
updateKeywords();
|
updateKeywords();
|
||||||
game.fireEvent(new GameEventPlayerStatsChanged(this));
|
game.fireEvent(new GameEventPlayerStatsChanged(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
public final KeywordsChange removeChangedKeywords(final Long timestamp) {
|
public final KeywordsChange removeChangedKeywords(final Long timestamp) {
|
||||||
KeywordsChange change = changedKeywords.remove(Long.valueOf(timestamp));
|
KeywordsChange change = changedKeywords.remove(timestamp);
|
||||||
if (change != null) {
|
if (change != null) {
|
||||||
|
getKeywordCard().removeChangedCardTraits(timestamp);
|
||||||
updateKeywords();
|
updateKeywords();
|
||||||
game.fireEvent(new GameEventPlayerStatsChanged(this));
|
game.fireEvent(new GameEventPlayerStatsChanged(this));
|
||||||
}
|
}
|
||||||
@@ -1100,6 +1104,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
for (final Entry<Long, KeywordsChange> ck : ImmutableList.copyOf(changedKeywords.entrySet())) {
|
for (final Entry<Long, KeywordsChange> ck : ImmutableList.copyOf(changedKeywords.entrySet())) {
|
||||||
if (ck.getValue().isEmpty() && changedKeywords.remove(ck.getKey()) != null) {
|
if (ck.getValue().isEmpty() && changedKeywords.remove(ck.getKey()) != null) {
|
||||||
keywordRemoved = true;
|
keywordRemoved = true;
|
||||||
|
getKeywordCard().removeChangedCardTraits(ck.getKey());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1178,33 +1183,17 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final boolean canBeTargetedBy(final SpellAbility sa) {
|
public final boolean canBeTargetedBy(final SpellAbility sa) {
|
||||||
if (hasKeyword("Shroud")) {
|
|
||||||
return false;
|
// CantTarget static abilities
|
||||||
}
|
for (final Card ca : getGame().getCardsIn(ZoneType.listValueOf("Battlefield,Command"))) {
|
||||||
if (hasKeyword("Hexproof")) {
|
for (final StaticAbility stAb : ca.getStaticAbilities()) {
|
||||||
final Player a = sa.getActivatingPlayer();
|
if (stAb.applyAbility("CantTarget", this, sa)) {
|
||||||
if (isOpponentOf(a)) {
|
|
||||||
boolean cancelHexproof = false;
|
|
||||||
for (String k : a.getKeywords()) {
|
|
||||||
if (k.startsWith("IgnoreHexproof")) {
|
|
||||||
String[] m = k.split(":");
|
|
||||||
if (isValid(m[1].split(","), a, sa.getHostCard(), sa)) {
|
|
||||||
cancelHexproof = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!cancelHexproof) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasProtectionFrom(sa.getHostCard())) {
|
return !hasProtectionFrom(sa.getHostCard());
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (!hasKeyword("You can't be the targets of spells or activated abilities") || (!sa.isSpell() && (!(sa instanceof AbilityActivated))));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -2971,4 +2960,26 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
|| !hasKeyword("Spells and abilities you control can't cause you to search your library.");
|
|| !hasKeyword("Spells and abilities you control can't cause you to search your library.");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Card getKeywordCard() {
|
||||||
|
if (keywordEffect != null) {
|
||||||
|
return keywordEffect;
|
||||||
|
}
|
||||||
|
|
||||||
|
final PlayerZone com = getZone(ZoneType.Command);
|
||||||
|
|
||||||
|
keywordEffect = new Card(game.nextCardId(), null, false, game);
|
||||||
|
keywordEffect.setImmutable(true);
|
||||||
|
keywordEffect.setOwner(this);
|
||||||
|
keywordEffect.setName("Keyword Effects");
|
||||||
|
keywordEffect.setImageKey(ImageKeys.HIDDEN_CARD);
|
||||||
|
keywordEffect.addType("Effect");
|
||||||
|
|
||||||
|
keywordEffect.updateStateForView();
|
||||||
|
|
||||||
|
com.add(keywordEffect);
|
||||||
|
|
||||||
|
this.updateZoneForView(com);
|
||||||
|
return keywordEffect;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package forge.game.player;
|
||||||
|
|
||||||
|
import forge.game.card.Card;
|
||||||
|
import forge.game.keyword.KeywordInterface;
|
||||||
|
import forge.game.staticability.StaticAbility;
|
||||||
|
|
||||||
|
public class PlayerFactoryUtil {
|
||||||
|
|
||||||
|
public static void addStaticAbility(final KeywordInterface inst, final Player player) {
|
||||||
|
final Card card = player.getKeywordCard();
|
||||||
|
String keyword = inst.getOriginal();
|
||||||
|
String effect = null;
|
||||||
|
if (keyword.startsWith("Hexproof")) {
|
||||||
|
final StringBuilder sbDesc = new StringBuilder("Hexproof");
|
||||||
|
final StringBuilder sbValid = new StringBuilder();
|
||||||
|
|
||||||
|
if (!keyword.equals("Hexproof")) {
|
||||||
|
final String[] k = keyword.split(":");
|
||||||
|
|
||||||
|
sbDesc.append(" from ").append(k[2]);
|
||||||
|
sbValid.append("| ValidSource$ ").append(k[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
effect = "Mode$ CantTarget | Hexproof$ True | ValidPlayer$ Player.You | Secondary$ True "
|
||||||
|
+ sbValid.toString() + " | Activator$ Opponent | EffectZone$ Command | Description$ "
|
||||||
|
+ sbDesc.toString() + " (" + inst.getReminderText() + ")";
|
||||||
|
} else if (keyword.equals("Shroud")) {
|
||||||
|
effect = "Mode$ CantTarget | Shroud$ True | ValidPlayer$ Player.You | Secondary$ True "
|
||||||
|
+ "| EffectZone$ Command | Description$ Shroud (" + inst.getReminderText() + ")";
|
||||||
|
}
|
||||||
|
if (effect != null) {
|
||||||
|
StaticAbility st = new StaticAbility(effect, card);
|
||||||
|
st.setIntrinsic(false);
|
||||||
|
inst.addStaticAbility(st);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addTriggerAbility(final KeywordInterface inst, Player player) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addReplacementEffect(final KeywordInterface inst, Player player) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addSpellAbility(final KeywordInterface inst, Player player) {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -391,6 +391,23 @@ public class StaticAbility extends CardTraitBase implements IIdentifiable, Clone
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final boolean applyAbility(final String mode, final Player player, final SpellAbility spellAbility) {
|
||||||
|
// don't apply the ability if it hasn't got the right mode
|
||||||
|
if (!getParam("Mode").equals(mode)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.isSuppressed() || !this.checkConditions()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode.equals("CantTarget")) {
|
||||||
|
return StaticAbilityCantTarget.applyCantTargetAbility(this, player, spellAbility);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public final boolean applyAbility(String mode, Card card, CounterType type) {
|
public final boolean applyAbility(String mode, Card card, CounterType type) {
|
||||||
|
|
||||||
// don't apply the ability if it hasn't got the right mode
|
// don't apply the ability if it hasn't got the right mode
|
||||||
|
|||||||
@@ -22,8 +22,6 @@ import forge.game.player.Player;
|
|||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
import forge.game.zone.ZoneType;
|
import forge.game.zone.ZoneType;
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Class StaticAbilityCantTarget.
|
* The Class StaticAbilityCantTarget.
|
||||||
*/
|
*/
|
||||||
@@ -32,7 +30,7 @@ public class StaticAbilityCantTarget {
|
|||||||
/**
|
/**
|
||||||
* Apply can't target ability.
|
* Apply can't target ability.
|
||||||
*
|
*
|
||||||
* @param staticAbility
|
* @param st
|
||||||
* the static ability
|
* the static ability
|
||||||
* @param card
|
* @param card
|
||||||
* the card
|
* the card
|
||||||
@@ -40,16 +38,19 @@ public class StaticAbilityCantTarget {
|
|||||||
* the spell/ability
|
* the spell/ability
|
||||||
* @return true, if successful
|
* @return true, if successful
|
||||||
*/
|
*/
|
||||||
public static boolean applyCantTargetAbility(final StaticAbility staticAbility, final Card card,
|
public static boolean applyCantTargetAbility(final StaticAbility st, final Card card,
|
||||||
final SpellAbility spellAbility) {
|
final SpellAbility spellAbility) {
|
||||||
final Map<String, String> params = staticAbility.getMapParams();
|
final Card hostCard = st.getHostCard();
|
||||||
final Card hostCard = staticAbility.getHostCard();
|
|
||||||
final Card source = spellAbility.getHostCard();
|
final Card source = spellAbility.getHostCard();
|
||||||
final Player activator = spellAbility.getActivatingPlayer();
|
final Player activator = spellAbility.getActivatingPlayer();
|
||||||
|
|
||||||
if (params.containsKey("AffectedZone")) {
|
if (st.hasParam("ValidPlayer")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (st.hasParam("AffectedZone")) {
|
||||||
boolean inZone = false;
|
boolean inZone = false;
|
||||||
for (final ZoneType zt : ZoneType.listValueOf(params.get("AffectedZone"))) {
|
for (final ZoneType zt : ZoneType.listValueOf(st.getParam("AffectedZone"))) {
|
||||||
if (card.isInZone(zt)) {
|
if (card.isInZone(zt)) {
|
||||||
inZone = true;
|
inZone = true;
|
||||||
break;
|
break;
|
||||||
@@ -65,38 +66,14 @@ public class StaticAbilityCantTarget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params.containsKey("ValidSA")
|
|
||||||
&& !spellAbility.isValid(params.get("ValidSA").split(","), hostCard.getController(), hostCard, spellAbility)) {
|
if (st.hasParam("ValidCard")
|
||||||
|
&& !card.isValid(st.getParam("ValidCard").split(","), hostCard.getController(), hostCard, null)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params.containsKey("ValidCard")
|
|
||||||
&& !card.isValid(params.get("ValidCard").split(","), hostCard.getController(), hostCard, null)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (params.containsKey("ValidSource")
|
if (st.hasParam("Hexproof") && (activator != null)) {
|
||||||
&& !source.isValid(params.get("ValidSource").split(","), hostCard.getController(), hostCard, null)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (params.containsKey("Activator") && (activator != null)
|
|
||||||
&& !activator.isValid(params.get("Activator"), hostCard.getController(), hostCard, spellAbility)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (spellAbility.getParam("ValidTgts")!=null &&
|
|
||||||
(params.containsKey("SourceCanOnlyTarget")
|
|
||||||
&& (!spellAbility.getParam("ValidTgts").contains(params.get("SourceCanOnlyTarget"))
|
|
||||||
|| spellAbility.getParam("ValidTgts").contains(","))
|
|
||||||
|| spellAbility.getParam("ValidTgts").contains("non" + params.get("SourceCanOnlyTarget")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (params.containsKey("Hexproof") && (activator != null)) {
|
|
||||||
for (String k : activator.getKeywords()) {
|
for (String k : activator.getKeywords()) {
|
||||||
if (k.startsWith("IgnoreHexproof")) {
|
if (k.startsWith("IgnoreHexproof")) {
|
||||||
String[] m = k.split(":");
|
String[] m = k.split(":");
|
||||||
@@ -106,8 +83,81 @@ public class StaticAbilityCantTarget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (st.hasParam("Shroud") && (activator != null)) {
|
||||||
|
for (String k : activator.getKeywords()) {
|
||||||
|
if (k.startsWith("IgnoreShroud")) {
|
||||||
|
String[] m = k.split(":");
|
||||||
|
if (card.isValid(m[1].split(","), activator, source, spellAbility)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return common(st, spellAbility);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean applyCantTargetAbility(final StaticAbility st, final Player player,
|
||||||
|
final SpellAbility spellAbility) {
|
||||||
|
final Card hostCard = st.getHostCard();
|
||||||
|
final Card source = spellAbility.getHostCard();
|
||||||
|
final Player activator = spellAbility.getActivatingPlayer();
|
||||||
|
|
||||||
|
if (st.hasParam("ValidCard") || st.hasParam("AffectedZone")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (st.hasParam("ValidPlayer")
|
||||||
|
&& !player.isValid(st.getParam("ValidPlayer").split(","), hostCard.getController(), hostCard, null)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (st.hasParam("Hexproof") && (activator != null)) {
|
||||||
|
for (String k : activator.getKeywords()) {
|
||||||
|
if (k.startsWith("IgnoreHexproof")) {
|
||||||
|
String[] m = k.split(":");
|
||||||
|
if (player.isValid(m[1].split(","), activator, source, spellAbility)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected static boolean common(final StaticAbility st, final SpellAbility spellAbility) {
|
||||||
|
final Card hostCard = st.getHostCard();
|
||||||
|
final Card source = spellAbility.getHostCard();
|
||||||
|
final Player activator = spellAbility.getActivatingPlayer();
|
||||||
|
|
||||||
|
if (st.hasParam("ValidSA")
|
||||||
|
&& !spellAbility.isValid(st.getParam("ValidSA").split(","), hostCard.getController(), hostCard, spellAbility)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (st.hasParam("ValidSource")
|
||||||
|
&& !source.isValid(st.getParam("ValidSource").split(","), hostCard.getController(), hostCard, null)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (st.hasParam("Activator") && (activator != null)
|
||||||
|
&& !activator.isValid(st.getParam("Activator"), hostCard.getController(), hostCard, spellAbility)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spellAbility.hasParam("ValidTgts") &&
|
||||||
|
(st.hasParam("SourceCanOnlyTarget")
|
||||||
|
&& (!spellAbility.getParam("ValidTgts").contains(st.getParam("SourceCanOnlyTarget"))
|
||||||
|
|| spellAbility.getParam("ValidTgts").contains(","))
|
||||||
|
|| spellAbility.getParam("ValidTgts").contains("non" + st.getParam("SourceCanOnlyTarget")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ ManaCost:4 G G
|
|||||||
Types:Legendary Creature Avatar
|
Types:Legendary Creature Avatar
|
||||||
PT:4/4
|
PT:4/4
|
||||||
K:Shroud
|
K:Shroud
|
||||||
A:AB$ Pump | Cost$ G | ValidTgts$ Player | Defined$ Targeted | TgtPrompt$ Select target player to be able to target Autumn Willow | KW$ Can target CardUIDSource with spells and abilities as though it didn't have shroud. | DefinedKW$ CardUIDSource | StackDescription$ Until end of turn, {p:Targeted} can target CARDNAME as though it didn't have shroud. | SpellDescription$ Until end of turn, Autumn Willow can be the target of spells and abilities controlled by target player as though it didn't have shroud.
|
A:AB$ Pump | Cost$ G | ValidTgts$ Player | Defined$ Targeted | TgtPrompt$ Select target player to be able to target Autumn Willow | KW$ IgnoreShroud:Card.CardUIDSource | DefinedKW$ CardUIDSource | UntilHostLeavesPlayOrEOT$ True | StackDescription$ Until end of turn, {p:Targeted} can target CARDNAME as though it didn't have shroud. | SpellDescription$ Until end of turn, Autumn Willow can be the target of spells and abilities controlled by target player as though it didn't have shroud.
|
||||||
AI:RemoveDeck:All
|
AI:RemoveDeck:All
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/autumn_willow.jpg
|
SVar:Picture:http://www.wizards.com/global/images/magic/general/autumn_willow.jpg
|
||||||
Oracle:Shroud (This creature can't be the target of spells or abilities.)\n{G}: Until end of turn, Autumn Willow can be the target of spells and abilities controlled by target player as though it didn't have shroud.
|
Oracle:Shroud (This creature can't be the target of spells or abilities.)\n{G}: Until end of turn, Autumn Willow can be the target of spells and abilities controlled by target player as though it didn't have shroud.
|
||||||
|
|||||||
@@ -4,6 +4,6 @@ Types:Sorcery
|
|||||||
A:SP$ Effect | Cost$ 1 W | Name$ Peace Talks Effect | StaticAbilities$ STCantAttack,STCantTarget,STCantTargetPlayer | Duration$ ThisTurnAndNextTurn | SpellDescription$ This turn and next turn, creatures can't attack, and players and permanents can't be the targets of spells or activated abilities.
|
A:SP$ Effect | Cost$ 1 W | Name$ Peace Talks Effect | StaticAbilities$ STCantAttack,STCantTarget,STCantTargetPlayer | Duration$ ThisTurnAndNextTurn | SpellDescription$ This turn and next turn, creatures can't attack, and players and permanents can't be the targets of spells or activated abilities.
|
||||||
SVar:STCantAttack:Mode$ CantAttack | EffectZone$ Command | ValidCard$ Creature | Description$ Creatures can't attack.
|
SVar:STCantAttack:Mode$ CantAttack | EffectZone$ Command | ValidCard$ Creature | Description$ Creatures can't attack.
|
||||||
SVar:STCantTarget:Mode$ CantTarget | ValidCard$ Permanent | EffectZone$ Command | ValidSA$ Spell,Activated | Description$ Permanents can't be the targets of spells or activated abilities.
|
SVar:STCantTarget:Mode$ CantTarget | ValidCard$ Permanent | EffectZone$ Command | ValidSA$ Spell,Activated | Description$ Permanents can't be the targets of spells or activated abilities.
|
||||||
SVar:STCantTargetPlayer:Mode$ Continuous | Affected$ Player | EffectZone$ Command | AddKeyword$ You can't be the targets of spells or activated abilities | Description$ Players can't be the targets of spells or activated abilities.
|
SVar:STCantTargetPlayer:Mode$ CantTarget | ValidPlayer$ Player | EffectZone$ Command | ValidSA$ Spell,Activated | Description$Players can't be the targets of spells or activated abilities.
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/peace_talks.jpg
|
SVar:Picture:http://www.wizards.com/global/images/magic/general/peace_talks.jpg
|
||||||
Oracle:This turn and next turn, creatures can't attack, and players and permanents can't be the targets of spells or activated abilities.
|
Oracle:This turn and next turn, creatures can't attack, and players and permanents can't be the targets of spells or activated abilities.
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ ManaCost:1 W U
|
|||||||
Types:Enchantment Aura
|
Types:Enchantment Aura
|
||||||
K:Enchant creature
|
K:Enchant creature
|
||||||
A:SP$ Attach | Cost$ 1 W U | ValidTgts$ Creature | AILogic$ Pump
|
A:SP$ Attach | Cost$ 1 W U | ValidTgts$ Creature | AILogic$ Pump
|
||||||
S:Mode$ Continuous | Affected$ Creature.EnchantedBy | AddToughness$ 2 | AddHiddenKeyword$ CARDNAME can't be the target of spells. | Description$ Enchanted creature gets +0/+2 and can't be the target of spells.
|
S:Mode$ Continuous | Affected$ Creature.EnchantedBy | AddToughness$ 2 | Description$ Enchanted creature gets +0/+2.
|
||||||
|
S:Mode$ CantTarget | ValidCard$ Creature.EnchantedBy | ValidSA$ Spell | Description$ Enchanted creature can't be the target of spells.
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/spectral_shield.jpg
|
SVar:Picture:http://www.wizards.com/global/images/magic/general/spectral_shield.jpg
|
||||||
Oracle:Enchant creature\nEnchanted creature gets +0/+2 and can't be the target of spells.
|
Oracle:Enchant creature\nEnchanted creature gets +0/+2 and can't be the target of spells.
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
Name:Veil of Summer
|
Name:Veil of Summer
|
||||||
ManaCost:G
|
ManaCost:G
|
||||||
Types:Instant
|
Types:Instant
|
||||||
A:SP$ Draw | Cost$ G | Defined$ You | ConditionCheckSVar$ X | ConditionSVarCompare$ GE1 | SubAbility$ DBEffect | SpellDescription$ Draw a card if an opponent has cast a blue or black spell this turn. Spells you control can't be countered this turn. You and permanents you control gain hexproof from blue and from black until end of turn. (You and they can't be the targets of blue or black spells or abilities your opponents control.)
|
A:SP$ Draw | Cost$ G | Defined$ You | ConditionCheckSVar$ X | ConditionSVarCompare$ GE1 |References$ X | SubAbility$ DBEffect | StackDescription$ SpellDescription | SpellDescription$ Draw a card if an opponent has cast a blue or black spell this turn. Spells you control can't be countered this turn. You and permanents you control gain hexproof from blue and from black until end of turn. (You and they can't be the targets of blue or black spells or abilities your opponents control.)
|
||||||
SVar:DBEffect:DB$ Effect | Name$ CARDNAME Effect | StaticAbilities$ AntiMagic | SubAbility$ DBPump
|
SVar:DBEffect:DB$ Effect | StaticAbilities$ AntiMagic | SubAbility$ DBPump
|
||||||
SVar:AntiMagic:Mode$ Continuous | Affected$ Card.YouCtrl | AffectedZone$ Stack | EffectZone$ Command | AddHiddenKeyword$ CARDNAME can't be countered. | Description$ Spells you control can't be countered this turn.
|
SVar:AntiMagic:Mode$ Continuous | Affected$ Card.YouCtrl | AffectedZone$ Stack | EffectZone$ Command | AddHiddenKeyword$ CARDNAME can't be countered. | Description$ Spells you control can't be countered this turn.
|
||||||
SVar:DBPump:DB$ Pump | Defined$ You | KW$ Hexproof:Card.Black:black & Hexproof:Card.Blue:blue | SubAbility$ DBPumpAll
|
SVar:DBPump:DB$ Pump | Defined$ You | KW$ Hexproof:Card.Black:black & Hexproof:Card.Blue:blue | SubAbility$ DBPumpAll
|
||||||
SVar:DBPumpAll:DB$ PumpAll | ValidCards$ Permanent.YouCtrl | KW$ Hexproof:Card.Black:black & Hexproof:Card.Blue:blue
|
SVar:DBPumpAll:DB$ PumpAll | ValidCards$ Permanent.YouCtrl | KW$ Hexproof:Card.Black:black & Hexproof:Card.Blue:blue
|
||||||
|
|||||||
Reference in New Issue
Block a user