Merge pull request #2548 from Card-Forge/IfReachStatic

Dragon Hunter as StaticAbility instead of fake Keyword
This commit is contained in:
Anthony Calosa
2023-02-24 14:43:52 +08:00
committed by GitHub
5 changed files with 51 additions and 51 deletions

View File

@@ -2000,11 +2000,6 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
if (keyword.startsWith("CantBeCounteredBy")) { if (keyword.startsWith("CantBeCounteredBy")) {
final String[] p = keyword.split(":"); final String[] p = keyword.split(":");
sbLong.append(p[2]).append("\r\n"); sbLong.append(p[2]).append("\r\n");
} else if (keyword.startsWith("IfReach")) {
String[] k = keyword.split(":");
sbLong.append(getName()).append(" can block ")
.append(CardType.getPluralType(k[1]))
.append(" as though it had reach.\r\n");
} else { } else {
sbLong.append(keyword).append("\r\n"); sbLong.append(keyword).append("\r\n");
} }
@@ -2313,11 +2308,6 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
sb.append(Localizer.getInstance().getMessage("lblReadAhead")).append(" (").append(Localizer.getInstance().getMessage("lblReadAheadDesc")); sb.append(Localizer.getInstance().getMessage("lblReadAhead")).append(" (").append(Localizer.getInstance().getMessage("lblReadAheadDesc"));
sb.append(" ").append(Localizer.getInstance().getMessage("lblSagaFooter")).append(" ").append(TextUtil.toRoman(getFinalChapterNr())).append("."); sb.append(" ").append(Localizer.getInstance().getMessage("lblSagaFooter")).append(" ").append(TextUtil.toRoman(getFinalChapterNr())).append(".");
sb.append(")").append("\r\n\r\n"); sb.append(")").append("\r\n\r\n");
} else if (keyword.startsWith("IfReach")) {
String[] k = keyword.split(":");
sbLong.append(getName()).append(" can block ")
.append(CardType.getPluralType(k[1]))
.append(" as though it had reach.\r\n");
} else if (keyword.startsWith("MayEffectFromOpening")) { } else if (keyword.startsWith("MayEffectFromOpening")) {
final String[] k = keyword.split(":"); final String[] k = keyword.split(":");
// need to get SpellDescription from Svar // need to get SpellDescription from Svar

View File

@@ -63,7 +63,7 @@ public final class CardUtil {
"Cycling", "Echo", "Kicker", "Flashback", "Madness", "Morph", "Cycling", "Echo", "Kicker", "Flashback", "Madness", "Morph",
"Affinity", "Entwine", "Splice", "Ninjutsu", "Presence", "Affinity", "Entwine", "Splice", "Ninjutsu", "Presence",
"Transmute", "Replicate", "Recover", "Squad", "Suspend", "Aura swap", "Transmute", "Replicate", "Recover", "Squad", "Suspend", "Aura swap",
"Fortify", "Transfigure", "Champion", "Evoke", "Prowl", "IfReach", "Fortify", "Transfigure", "Champion", "Evoke", "Prowl",
"Reinforce", "Unearth", "Level up", "Miracle", "Overload", "Cleave", "Reinforce", "Unearth", "Level up", "Miracle", "Overload", "Cleave",
"Scavenge", "Encore", "Bestow", "Outlast", "Dash", "Surge", "Emerge", "Hexproof:", "Scavenge", "Encore", "Bestow", "Outlast", "Dash", "Surge", "Emerge", "Hexproof:",
"etbCounter", "Reflect", "Ward").build(); "etbCounter", "Reflect", "Ward").build();

View File

@@ -17,7 +17,6 @@
*/ */
package forge.game.staticability; package forge.game.staticability;
import forge.game.Game;
import forge.game.GameEntity; import forge.game.GameEntity;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
@@ -47,8 +46,6 @@ public class StaticAbilityCanAttackDefender {
} }
public static boolean applyCanAttackAbility(final StaticAbility stAb, final Card card, final GameEntity target) { public static boolean applyCanAttackAbility(final StaticAbility stAb, final Card card, final GameEntity target) {
final Card hostCard = stAb.getHostCard();
final Game game = hostCard.getGame();
if (!stAb.matchesValidParam("ValidCard", card)) { if (!stAb.matchesValidParam("ValidCard", card)) {
return false; return false;

View File

@@ -30,7 +30,6 @@ import forge.game.card.CardCollectionView;
import forge.game.card.CardPredicates; import forge.game.card.CardPredicates;
import forge.game.cost.Cost; import forge.game.cost.Cost;
import forge.game.keyword.Keyword; import forge.game.keyword.Keyword;
import forge.game.keyword.KeywordInterface;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
@@ -40,7 +39,8 @@ import forge.game.zone.ZoneType;
public class StaticAbilityCantAttackBlock { public class StaticAbilityCantAttackBlock {
public static String CantAttackMode = "CantAttack"; public static String CantAttackMode = "CantAttack";
public static String CantBlockByMode = "CantBlockBy"; public static String CantBlockByMode = "CantBlockBy";
public static String CanAttackHasteMode = "CanAttackIfHaste"; public static String CanAttackIfHasteMode = "CanAttackIfHaste";
public static String CanBlockIfReachMode = "CanBlockIfReach";
public static String MinMaxBlockerMode = "MinMaxBlocker"; public static String MinMaxBlockerMode = "MinMaxBlocker";
public static boolean cantAttack(final Card attacker, final GameEntity defender) { public static boolean cantAttack(final Card attacker, final GameEntity defender) {
@@ -67,10 +67,8 @@ public class StaticAbilityCantAttackBlock {
/** /**
* TODO Write javadoc for this method. * TODO Write javadoc for this method.
* *
* @param stAb * @param stAb a StaticAbility
* a StaticAbility * @param card the card
* @param card
* the card
* @return a Cost * @return a Cost
*/ */
public static boolean applyCantAttackAbility(final StaticAbility stAb, final Card card, final GameEntity target) { public static boolean applyCantAttackAbility(final StaticAbility stAb, final Card card, final GameEntity target) {
@@ -86,7 +84,7 @@ public class StaticAbilityCantAttackBlock {
} }
if (stAb.hasParam("DefenderKeyword")) { if (stAb.hasParam("DefenderKeyword")) {
//check for "can attack as if didn't have defender" static // check for "can attack as if didn't have defender" static
if (StaticAbilityCanAttackDefender.canAttack(card, target)) { if (StaticAbilityCanAttackDefender.canAttack(card, target)) {
return false; return false;
} }
@@ -97,19 +95,20 @@ public class StaticAbilityCantAttackBlock {
if (stAb.hasParam("UnlessDefenderControls")) { if (stAb.hasParam("UnlessDefenderControls")) {
String type = stAb.getParam("UnlessDefenderControls"); String type = stAb.getParam("UnlessDefenderControls");
CardCollectionView list = defender.getCardsIn(ZoneType.Battlefield); CardCollectionView list = defender.getCardsIn(ZoneType.Battlefield);
if (Iterables.any(list, CardPredicates.restriction(type.split(","), hostCard.getController(), hostCard, stAb))) { if (Iterables.any(list,
CardPredicates.restriction(type.split(","), hostCard.getController(), hostCard, stAb))) {
return false; return false;
} }
} }
if (stAb.hasParam("IfDefenderControls")) { if (stAb.hasParam("IfDefenderControls")) {
String type = stAb.getParam("IfDefenderControls"); String type = stAb.getParam("IfDefenderControls");
CardCollectionView list = defender.getCardsIn(ZoneType.Battlefield); CardCollectionView list = defender.getCardsIn(ZoneType.Battlefield);
if (!Iterables.any(list, CardPredicates.restriction(type.split(","), hostCard.getController(), hostCard, stAb))) { if (!Iterables.any(list,
CardPredicates.restriction(type.split(","), hostCard.getController(), hostCard, stAb))) {
return false; return false;
} }
} }
if (stAb.hasParam("DefenderNotNearestToYouInChosenDirection") if (stAb.hasParam("DefenderNotNearestToYouInChosenDirection") && (hostCard.getChosenDirection() == null
&& (hostCard.getChosenDirection() == null
|| defender.equals(game.getNextPlayerAfter(card.getController(), hostCard.getChosenDirection())))) { || defender.equals(game.getNextPlayerAfter(card.getController(), hostCard.getChosenDirection())))) {
return false; return false;
} }
@@ -123,8 +122,7 @@ public class StaticAbilityCantAttackBlock {
return true; return true;
} }
public static boolean cantBlockBy(final Card attacker, final Card blocker) public static boolean cantBlockBy(final Card attacker, final Card blocker) {
{
for (final Card ca : attacker.getGame().getCardsIn(ZoneType.STATIC_ABILITIES_SOURCE_ZONES)) { for (final Card ca : attacker.getGame().getCardsIn(ZoneType.STATIC_ABILITIES_SOURCE_ZONES)) {
for (final StaticAbility stAb : ca.getStaticAbilities()) { for (final StaticAbility stAb : ca.getStaticAbilities()) {
if (!stAb.checkConditions(CantBlockByMode)) { if (!stAb.checkConditions(CantBlockByMode)) {
@@ -140,6 +138,7 @@ public class StaticAbilityCantAttackBlock {
/** /**
* returns true if attacker can't be blocked by blocker * returns true if attacker can't be blocked by blocker
*
* @param stAb * @param stAb
* @param attacker * @param attacker
* @param blocker * @param blocker
@@ -155,18 +154,9 @@ public class StaticAbilityCantAttackBlock {
for (final String v : stAb.getParam("ValidBlocker").split(",")) { for (final String v : stAb.getParam("ValidBlocker").split(",")) {
if (blocker != null && blocker.isValid(v, host.getController(), host, stAb)) { if (blocker != null && blocker.isValid(v, host.getController(), host, stAb)) {
stillblock = false; stillblock = false;
//Dragon Hunter check // Dragon Hunter check
if (v.contains("withoutReach") && blocker.hasStartOfKeyword("IfReach")) { if (v.contains("withoutReach") && canBlockIfReach(attacker, blocker)) {
for (KeywordInterface inst : blocker.getKeywords()) {
String k = inst.getOriginal();
if (k.startsWith("IfReach")) {
String[] n = k.split(":");
if (attacker.getType().hasCreatureType(n[1])) {
stillblock = true; stillblock = true;
break;
}
}
}
} }
if (!stillblock) { if (!stillblock) {
break; break;
@@ -192,13 +182,36 @@ public class StaticAbilityCantAttackBlock {
return true; return true;
} }
public static boolean canBlockIfReach(final Card attacker, final Card blocker) {
for (final Card ca : attacker.getGame().getCardsIn(ZoneType.STATIC_ABILITIES_SOURCE_ZONES)) {
for (final StaticAbility stAb : ca.getStaticAbilities()) {
if (!stAb.checkConditions(CanBlockIfReachMode)) {
continue;
}
if (applyCanBlockIfReachAbility(stAb, attacker, blocker)) {
return true;
}
}
}
return false;
}
public static boolean applyCanBlockIfReachAbility(final StaticAbility stAb, final Card attacker,
final Card blocker) {
if (!stAb.matchesValidParam("ValidAttacker", attacker)) {
return false;
}
if (!stAb.matchesValidParam("ValidBlocker", blocker)) {
return false;
}
return true;
}
/** /**
* TODO Write javadoc for this method. * TODO Write javadoc for this method.
* *
* @param stAb * @param stAb a StaticAbility
* a StaticAbility * @param attacker the card
* @param attacker
* the card
* @return a Cost * @return a Cost
*/ */
public static Cost getAttackCost(final StaticAbility stAb, final Card attacker, final GameEntity target) { public static Cost getAttackCost(final StaticAbility stAb, final Card attacker, final GameEntity target) {
@@ -235,10 +248,8 @@ public class StaticAbilityCantAttackBlock {
/** /**
* TODO Write javadoc for this method. * TODO Write javadoc for this method.
* *
* @param stAb * @param stAb a StaticAbility
* a StaticAbility * @param blocker the card
* @param blocker
* the card
* @return a Cost * @return a Cost
*/ */
public static Cost getBlockCost(final StaticAbility stAb, final Card blocker, final GameEntity attacker) { public static Cost getBlockCost(final StaticAbility stAb, final Card blocker, final GameEntity attacker) {
@@ -266,7 +277,7 @@ public class StaticAbilityCantAttackBlock {
} }
for (final Card ca : game.getCardsIn(ZoneType.STATIC_ABILITIES_SOURCE_ZONES)) { for (final Card ca : game.getCardsIn(ZoneType.STATIC_ABILITIES_SOURCE_ZONES)) {
for (final StaticAbility stAb : ca.getStaticAbilities()) { for (final StaticAbility stAb : ca.getStaticAbilities()) {
if (!stAb.checkConditions(CanAttackHasteMode)) { if (!stAb.checkConditions(CanAttackIfHasteMode)) {
continue; continue;
} }
if (applyCanAttackHasteAbility(stAb, attacker, defender)) { if (applyCanAttackHasteAbility(stAb, attacker, defender)) {
@@ -277,7 +288,8 @@ public class StaticAbilityCantAttackBlock {
return false; return false;
} }
public static boolean applyCanAttackHasteAbility(final StaticAbility stAb, final Card card, final GameEntity target) { public static boolean applyCanAttackHasteAbility(final StaticAbility stAb, final Card card,
final GameEntity target) {
if (!stAb.matchesValidParam("ValidCard", card)) { if (!stAb.matchesValidParam("ValidCard", card)) {
return false; return false;
} }
@@ -313,7 +325,8 @@ public class StaticAbilityCantAttackBlock {
return result; return result;
} }
public static void applyMinMaxBlockerAbility(final StaticAbility stAb, final Card attacker, final Player defender, MutablePair<Integer, Integer> result) { public static void applyMinMaxBlockerAbility(final StaticAbility stAb, final Card attacker, final Player defender,
MutablePair<Integer, Integer> result) {
if (!stAb.matchesValidParam("ValidCard", attacker)) { if (!stAb.matchesValidParam("ValidCard", attacker)) {
return; return;
} }

View File

@@ -3,5 +3,5 @@ ManaCost:W
Types:Creature Human Warrior Types:Creature Human Warrior
PT:2/1 PT:2/1
K:Protection from Dragons K:Protection from Dragons
K:IfReach:Dragon S:Mode$ CanBlockIfReach | ValidAttacker$ Dragon | ValidBlocker$ Card.Self | Description$ CARDNAME can block Dragons as though it had reach.
Oracle:Protection from Dragons\nDragon Hunter can block Dragons as though it had reach. Oracle:Protection from Dragons\nDragon Hunter can block Dragons as though it had reach.