mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-18 19:58:00 +00:00
Hexproof: is now done as CantTarget with special shared handling
This commit is contained in:
@@ -1526,6 +1526,10 @@ public class Card extends GameEntity implements Comparable<Card> {
|
|||||||
sbx.append(" (" + inst.getReminderText() + ")");
|
sbx.append(" (" + inst.getReminderText() + ")");
|
||||||
sbLong.append(sbx).append("\r\n");
|
sbLong.append(sbx).append("\r\n");
|
||||||
}
|
}
|
||||||
|
} else if (keyword.startsWith("Hexproof:")) {
|
||||||
|
final String k[] = keyword.split(":");
|
||||||
|
sbLong.append("Hexproof from ").append(k[2])
|
||||||
|
.append(" (").append(inst.getReminderText()).append(")").append("\r\n");
|
||||||
} else if (keyword.endsWith(".") && !keyword.startsWith("Haunt")) {
|
} else if (keyword.endsWith(".") && !keyword.startsWith("Haunt")) {
|
||||||
sbLong.append(keyword).append("\r\n");
|
sbLong.append(keyword).append("\r\n");
|
||||||
} else if (keyword.startsWith("Presence")) {
|
} else if (keyword.startsWith("Presence")) {
|
||||||
@@ -4975,13 +4979,6 @@ public class Card extends GameEntity implements Comparable<Card> {
|
|||||||
result.setFalse();
|
result.setFalse();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "Hexproof":
|
|
||||||
if (sa.getActivatingPlayer().getOpponents().contains(getController())) {
|
|
||||||
if (!sa.getActivatingPlayer().hasKeyword("Spells and abilities you control can target hexproof creatures")) {
|
|
||||||
result.setFalse();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "CARDNAME can't be enchanted.":
|
case "CARDNAME can't be enchanted.":
|
||||||
if (source.isAura()) {
|
if (source.isAura()) {
|
||||||
result.setFalse();
|
result.setFalse();
|
||||||
|
|||||||
@@ -1866,6 +1866,7 @@ public class CardFactoryUtil {
|
|||||||
CardCollectionView cardlist = p.getGame().getCardsIn(zones);
|
CardCollectionView cardlist = p.getGame().getCardsIn(zones);
|
||||||
final List<String> landkw = Lists.newArrayList();
|
final List<String> landkw = Lists.newArrayList();
|
||||||
final List<String> protectionkw = Lists.newArrayList();
|
final List<String> protectionkw = Lists.newArrayList();
|
||||||
|
final List<String> hexproofkw = Lists.newArrayList();
|
||||||
final List<String> allkw = Lists.newArrayList();
|
final List<String> allkw = Lists.newArrayList();
|
||||||
|
|
||||||
for (Card c : CardLists.getValidCards(cardlist, restrictions, p, host, null)) {
|
for (Card c : CardLists.getValidCards(cardlist, restrictions, p, host, null)) {
|
||||||
@@ -1879,6 +1880,10 @@ public class CardFactoryUtil {
|
|||||||
if (!protectionkw.contains(k)) {
|
if (!protectionkw.contains(k)) {
|
||||||
protectionkw.add(k);
|
protectionkw.add(k);
|
||||||
}
|
}
|
||||||
|
} else if (k.startsWith("Hexproof")) {
|
||||||
|
if (!hexproofkw.contains(k)) {
|
||||||
|
hexproofkw.add(k);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!allkw.contains(k)) {
|
if (!allkw.contains(k)) {
|
||||||
allkw.add(k);
|
allkw.add(k);
|
||||||
@@ -1890,6 +1895,8 @@ public class CardFactoryUtil {
|
|||||||
filteredkw.addAll(protectionkw);
|
filteredkw.addAll(protectionkw);
|
||||||
} else if (keyword.equals("Landwalk")) {
|
} else if (keyword.equals("Landwalk")) {
|
||||||
filteredkw.addAll(landkw);
|
filteredkw.addAll(landkw);
|
||||||
|
} else if (keyword.equals("Hexproof")) {
|
||||||
|
filteredkw.addAll(hexproofkw);
|
||||||
} else if (allkw.contains(keyword)) {
|
} else if (allkw.contains(keyword)) {
|
||||||
filteredkw.add(keyword);
|
filteredkw.add(keyword);
|
||||||
}
|
}
|
||||||
@@ -4202,6 +4209,21 @@ public class CardFactoryUtil {
|
|||||||
effect = "Mode$ RaiseCost | ValidCard$ Card.Self | Type$ Spell | Secondary$ True"
|
effect = "Mode$ RaiseCost | ValidCard$ Card.Self | Type$ Spell | Secondary$ True"
|
||||||
+ " | Amount$ Escalate | Cost$ "+ manacost +" | EffectZone$ All"
|
+ " | Amount$ Escalate | Cost$ "+ manacost +" | EffectZone$ All"
|
||||||
+ " | Description$ " + sb.toString() + " (" + inst.getReminderText() + ")";
|
+ " | Description$ " + sb.toString() + " (" + inst.getReminderText() + ")";
|
||||||
|
} else 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 | ValidCard$ Card.Self | Secondary$ True"
|
||||||
|
+ sbValid.toString() + " | Activator$ Opponent | Description$ "
|
||||||
|
+ sbDesc.toString() + " (" + 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];
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ public final class CardUtil {
|
|||||||
"Transmute", "Replicate", "Recover", "Suspend", "Aura swap",
|
"Transmute", "Replicate", "Recover", "Suspend", "Aura swap",
|
||||||
"Fortify", "Transfigure", "Champion", "Evoke", "Prowl", "IfReach",
|
"Fortify", "Transfigure", "Champion", "Evoke", "Prowl", "IfReach",
|
||||||
"Reinforce", "Unearth", "Level up", "Miracle", "Overload",
|
"Reinforce", "Unearth", "Level up", "Miracle", "Overload",
|
||||||
"Scavenge", "Bestow", "Outlast", "Dash", "Renown", "Surge", "Emerge").build();
|
"Scavenge", "Bestow", "Outlast", "Dash", "Renown", "Surge", "Emerge", "Hexproof:").build();
|
||||||
/** List of keyword endings of keywords that could be modified by text changes. */
|
/** List of keyword endings of keywords that could be modified by text changes. */
|
||||||
public static final ImmutableList<String> modifiableKeywordEndings = ImmutableList.<String>builder().add(
|
public static final ImmutableList<String> modifiableKeywordEndings = ImmutableList.<String>builder().add(
|
||||||
"walk", "cycling", "offering").build();
|
"walk", "cycling", "offering").build();
|
||||||
|
|||||||
37
forge-game/src/main/java/forge/game/keyword/Hexproof.java
Normal file
37
forge-game/src/main/java/forge/game/keyword/Hexproof.java
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
package forge.game.keyword;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
public class Hexproof extends KeywordInstance<Hexproof> {
|
||||||
|
private String type = "";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void parse(String details) {
|
||||||
|
if (!details.isEmpty()) {
|
||||||
|
type = details.split(":")[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String formatReminderText(String reminderText) {
|
||||||
|
if (type.isEmpty()) {
|
||||||
|
return "This can't be the target of spells or abilities your opponents control.";
|
||||||
|
}
|
||||||
|
return String.format(reminderText, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see forge.game.keyword.KeywordInstance#redundant(java.util.Collection)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean redundant(Collection<KeywordInterface> list) {
|
||||||
|
for (KeywordInterface i : list) {
|
||||||
|
if (i.getOriginal().equals(getOriginal())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -74,7 +74,7 @@ public enum Keyword {
|
|||||||
GRAVESTORM(SimpleKeyword.class, false, "When you cast this spell, copy it for each permanent that was put into a graveyard from the battlefield this turn. You may choose new targets for the copies."),
|
GRAVESTORM(SimpleKeyword.class, false, "When you cast this spell, copy it for each permanent that was put into a graveyard from the battlefield this turn. You may choose new targets for the copies."),
|
||||||
HASTE(SimpleKeyword.class, true, "This creature can attack and {T} as soon as it comes under your control."),
|
HASTE(SimpleKeyword.class, true, "This creature can attack and {T} as soon as it comes under your control."),
|
||||||
HAUNT(SimpleKeyword.class, false, "When this is put into a graveyard, exile it haunting target creature."),
|
HAUNT(SimpleKeyword.class, false, "When this is put into a graveyard, exile it haunting target creature."),
|
||||||
HEXPROOF(SimpleKeyword.class, true, "This can't be the target of spells or abilities your opponents control."),
|
HEXPROOF(Hexproof.class, false, "This can't be the target of %s spells or abilities your opponents control."),
|
||||||
HIDEAWAY(SimpleKeyword.class, false, "This land enters the battlefield tapped. When it does, look at the top four cards of your library, exile one face down, then put the rest on the bottom of your library."),
|
HIDEAWAY(SimpleKeyword.class, false, "This land enters the battlefield tapped. When it does, look at the top four cards of your library, exile one face down, then put the rest on the bottom of your library."),
|
||||||
HORSEMANSHIP(SimpleKeyword.class, true, "This creature can't be blocked except by creatures with horsemanship."),
|
HORSEMANSHIP(SimpleKeyword.class, true, "This creature can't be blocked except by creatures with horsemanship."),
|
||||||
IMPROVISE(SimpleKeyword.class, true, "Your artifacts can help cast this spell. Each artifact you tap after you're done activating mana abilities pays for {1}."),
|
IMPROVISE(SimpleKeyword.class, true, "Your artifacts can help cast this spell. Each artifact you tap after you're done activating mana abilities pays for {1}."),
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ public class KeywordCollection implements Iterable<String>, Serializable {
|
|||||||
public boolean insert(KeywordInterface inst) {
|
public boolean insert(KeywordInterface inst) {
|
||||||
Keyword keyword = inst.getKeyword();
|
Keyword keyword = inst.getKeyword();
|
||||||
Collection<KeywordInterface> list = map.get(keyword);
|
Collection<KeywordInterface> list = map.get(keyword);
|
||||||
if (list.isEmpty() || !keyword.isMultipleRedundant) {
|
if (list.isEmpty() || !inst.redundant(list)) {
|
||||||
list.add(inst);
|
list.add(inst);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -87,7 +87,7 @@ public class KeywordCollection implements Iterable<String>, Serializable {
|
|||||||
boolean result = false;
|
boolean result = false;
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
KeywordInterface k = it.next();
|
KeywordInterface k = it.next();
|
||||||
if (keyword.equals(k.getOriginal())) {
|
if (k.getOriginal().startsWith(keyword)) {
|
||||||
it.remove();
|
it.remove();
|
||||||
result = true;
|
result = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -217,4 +217,12 @@ public abstract class KeywordInstance<T extends KeywordInstance<?>> implements K
|
|||||||
public String toString() {
|
public String toString() {
|
||||||
return this.getOriginal();
|
return this.getOriginal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see forge.game.keyword.KeywordInterface#redundant(java.util.Collection)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean redundant(Collection<KeywordInterface> list) {
|
||||||
|
return !list.isEmpty() && keyword.isMultipleRedundant;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,4 +50,6 @@ public interface KeywordInterface extends Cloneable {
|
|||||||
public Collection<StaticAbility> getStaticAbilities();
|
public Collection<StaticAbility> getStaticAbilities();
|
||||||
|
|
||||||
public KeywordInterface copy(final Card host, final boolean lki);
|
public KeywordInterface copy(final Card host, final boolean lki);
|
||||||
|
|
||||||
|
public boolean redundant(final Collection<KeywordInterface> list);
|
||||||
}
|
}
|
||||||
@@ -84,6 +84,11 @@ public class StaticAbilityCantTarget {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (params.containsKey("Hexproof") && (activator != null)) {
|
||||||
|
if (activator.hasKeyword("Spells and abilities you control can target hexproof creatures")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
9
forge-gui/res/cardsfolder/upcoming/knight_of_grace.txt
Normal file
9
forge-gui/res/cardsfolder/upcoming/knight_of_grace.txt
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
Name:Knight of Grace
|
||||||
|
ManaCost:1 W
|
||||||
|
Types:Creature Human Knight
|
||||||
|
PT:2/2
|
||||||
|
K:First Strike
|
||||||
|
K:Hexproof:Card.Black:black
|
||||||
|
S:Mode$ Continuous | Affected$ Card.Self | AddPower$ 1 | IsPresent$ Permanent.Black | Description$ CARDNAME gets +1/+0 as long as any player controls a black permanent.
|
||||||
|
SVar:Picture:http://www.wizards.com/global/images/magic/general/knight_of_grace.jpg
|
||||||
|
Oracle:First strike\nHexproof from black (This creature can't be the target of black spells or abilities your opponents control.)\nKnight of Grace gets +1/+0 as long as any player controls a black permanent.
|
||||||
9
forge-gui/res/cardsfolder/upcoming/knight_of_malice.txt
Normal file
9
forge-gui/res/cardsfolder/upcoming/knight_of_malice.txt
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
Name:Knight of Malice
|
||||||
|
ManaCost:1 B
|
||||||
|
Types:Creature Human Knight
|
||||||
|
PT:2/2
|
||||||
|
K:First Strike
|
||||||
|
K:Hexproof:Card.White:white
|
||||||
|
S:Mode$ Continuous | Affected$ Card.Self | AddPower$ 1 | IsPresent$ Permanent.White | Description$ CARDNAME gets +1/+0 as long as any player controls a white permanent.
|
||||||
|
SVar:Picture:http://www.wizards.com/global/images/magic/general/knight_of_malice.jpg
|
||||||
|
Oracle:First strike\nHexproof from white (This creature can't be the target of white spells or abilities your opponents control.)\nKnight of Malice gets +1/+0 as long as any player controls a white permanent.
|
||||||
Reference in New Issue
Block a user