mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-18 19:58:00 +00:00
CardFactoryUtil: make CantBeBlockedBy into new StaticAbility
This commit is contained in:
@@ -18,7 +18,6 @@
|
||||
package forge.game.card;
|
||||
|
||||
import com.esotericsoftware.minlog.Log;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.*;
|
||||
import forge.GameCommand;
|
||||
import forge.ImageKeys;
|
||||
@@ -1537,6 +1536,7 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
sbLong.append(keyword).append("\r\n");
|
||||
} else if (keyword.startsWith("Strive") || keyword.startsWith("Escalate")
|
||||
|| keyword.startsWith("ETBReplacement")
|
||||
|| keyword.startsWith("CantBeBlockedBy ")
|
||||
|| keyword.equals("CARDNAME enters the battlefield tapped.")
|
||||
|| keyword.startsWith("UpkeepCost")) {
|
||||
} else if (keyword.startsWith("Provoke") || keyword.startsWith("Ingest") || keyword.equals("Unleash")
|
||||
@@ -1595,12 +1595,9 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
|| keyword.startsWith("Amplify") || keyword.startsWith("Ninjutsu")
|
||||
|| keyword.startsWith("Cycling") || keyword.startsWith("TypeCycling")) {
|
||||
// keyword parsing takes care of adding a proper description
|
||||
} else if (keyword.startsWith("CantBeBlockedBy")) {
|
||||
} else if (keyword.startsWith("CantBeBlockedByAmount")) {
|
||||
sbLong.append(getName()).append(" can't be blocked ");
|
||||
if (keyword.startsWith("CantBeBlockedByAmount"))
|
||||
sbLong.append(getTextForKwCantBeBlockedByAmount(keyword));
|
||||
else
|
||||
sbLong.append(getTextForKwCantBeBlockedByType(keyword));
|
||||
} else if (keyword.startsWith("CantBlock")) {
|
||||
sbLong.append(getName()).append(" can't block ");
|
||||
if (keyword.contains("CardUID")) {
|
||||
@@ -1657,112 +1654,6 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
return byClause + Lang.nounWithNumeral(cnt, isLT ? "or more creature" : "creature");
|
||||
}
|
||||
|
||||
private static String getTextForKwCantBeBlockedByType(final String keyword) {
|
||||
boolean negative = true;
|
||||
final List<String> subs = Lists.newArrayList(TextUtil.split(keyword.split(" ", 2)[1], ','));
|
||||
final List<List<String>> subsAnd = Lists.newArrayList();
|
||||
final List<String> orClauses = Lists.newArrayList();
|
||||
for (final String expession : subs) {
|
||||
final List<String> parts = Lists.newArrayList(expession.split("[.+]"));
|
||||
for (int p = 0; p < parts.size(); p++) {
|
||||
final String part = parts.get(p);
|
||||
if (part.equalsIgnoreCase("creature")) {
|
||||
parts.remove(p--);
|
||||
continue;
|
||||
}
|
||||
// based on suppossition that each expression has at least 1 predicate except 'creature'
|
||||
negative &= part.contains("non") || part.contains("without");
|
||||
}
|
||||
subsAnd.add(parts);
|
||||
}
|
||||
|
||||
final boolean allNegative = negative;
|
||||
final String byClause = allNegative ? "except by " : "by ";
|
||||
|
||||
final Function<Pair<Boolean, String>, String> withToString = new Function<Pair<Boolean, String>, String>() {
|
||||
@Override
|
||||
public String apply(Pair<Boolean, String> inp) {
|
||||
boolean useNon = inp.getKey() == allNegative;
|
||||
return (useNon ? "*NO* " : "") + inp.getRight();
|
||||
}
|
||||
};
|
||||
|
||||
for (final List<String> andOperands : subsAnd) {
|
||||
final List<Pair<Boolean, String>> prependedAdjectives = Lists.newArrayList();
|
||||
final List<Pair<Boolean, String>> postponedAdjectives = Lists.newArrayList();
|
||||
String creatures = null;
|
||||
|
||||
for (String part : andOperands) {
|
||||
boolean positive = true;
|
||||
if (part.startsWith("non")) {
|
||||
part = part.substring(3);
|
||||
positive = false;
|
||||
}
|
||||
if (part.startsWith("with")) {
|
||||
positive = !part.startsWith("without");
|
||||
postponedAdjectives.add(Pair.of(positive, part.substring(positive ? 4 : 7)));
|
||||
} else if (part.startsWith("powerLEX")) {// Kraken of the Straits
|
||||
postponedAdjectives.add(Pair.of(true, "power less than the number of islands you control"));
|
||||
} else if (part.startsWith("power")) {
|
||||
int kwLength = 5;
|
||||
String opName = Expressions.operatorName(part.substring(kwLength, kwLength + 2));
|
||||
String operand = part.substring(kwLength + 2);
|
||||
postponedAdjectives.add(Pair.of(true, "power" + opName + operand));
|
||||
} else if (CardType.isACreatureType(part)) {
|
||||
if (creatures != null && CardType.isACreatureType(creatures)) { // e.g. Kor Castigator
|
||||
creatures = StringUtils.capitalize(Lang.getPlural(part)) + creatures;
|
||||
} else {
|
||||
creatures = StringUtils.capitalize(Lang.getPlural(part)) + (creatures == null ? "" : " or " + creatures);
|
||||
}
|
||||
// Kor Castigator and other similar creatures with composite subtype Eldrazi Scion in their text
|
||||
creatures = TextUtil.fastReplace(creatures, "Scions or Eldrazis", "Eldrazi Scions");
|
||||
} else {
|
||||
prependedAdjectives.add(Pair.of(positive, part.toLowerCase()));
|
||||
}
|
||||
}
|
||||
|
||||
StringBuilder sbShort = new StringBuilder();
|
||||
if (allNegative) {
|
||||
boolean isFirst = true;
|
||||
for (Pair<Boolean, String> pre : prependedAdjectives) {
|
||||
if (isFirst) isFirst = false;
|
||||
else sbShort.append(" and/or ");
|
||||
|
||||
boolean useNon = pre.getKey() == allNegative;
|
||||
if (useNon) sbShort.append("non-");
|
||||
sbShort.append(pre.getValue()).append(" ").append(creatures == null ? "creatures" : creatures);
|
||||
}
|
||||
if (prependedAdjectives.isEmpty())
|
||||
sbShort.append(creatures == null ? "creatures" : creatures);
|
||||
|
||||
if (!postponedAdjectives.isEmpty()) {
|
||||
if (!prependedAdjectives.isEmpty()) {
|
||||
sbShort.append(" and/or creatures");
|
||||
}
|
||||
|
||||
sbShort.append(" with ");
|
||||
sbShort.append(Lang.joinHomogenous(postponedAdjectives, withToString, allNegative ? "or" : "and"));
|
||||
}
|
||||
|
||||
} else {
|
||||
for (Pair<Boolean, String> pre : prependedAdjectives) {
|
||||
boolean useNon = pre.getKey() == allNegative;
|
||||
if (useNon) sbShort.append("non-");
|
||||
sbShort.append(pre.getValue()).append(" ");
|
||||
}
|
||||
sbShort.append(creatures == null ? "creatures" : creatures);
|
||||
|
||||
if (!postponedAdjectives.isEmpty()) {
|
||||
sbShort.append(" with ");
|
||||
sbShort.append(Lang.joinHomogenous(postponedAdjectives, withToString, allNegative ? "or" : "and"));
|
||||
}
|
||||
|
||||
}
|
||||
orClauses.add(sbShort.toString());
|
||||
}
|
||||
return byClause + StringUtils.join(orClauses, " or ") + ".";
|
||||
}
|
||||
|
||||
// get the text of the abilities of a card
|
||||
public String getAbilityText() {
|
||||
return getAbilityText(currentState);
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
package forge.game.card;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.Iterables;
|
||||
@@ -51,10 +52,12 @@ import forge.game.trigger.TriggerHandler;
|
||||
import forge.game.zone.Zone;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.util.Aggregates;
|
||||
import forge.util.Expressions;
|
||||
import forge.util.Lang;
|
||||
import forge.util.TextUtil;
|
||||
import forge.util.collect.FCollectionView;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
@@ -4226,6 +4229,11 @@ public class CardFactoryUtil {
|
||||
} else if (keyword.equals("Undaunted")) {
|
||||
effect = "Mode$ ReduceCost | ValidCard$ Card.Self | Type$ Spell | Secondary$ True"
|
||||
+ "| Amount$ Undaunted | EffectZone$ All | Description$ Undaunted (" + inst.getReminderText() + ")";
|
||||
} else if (keyword.startsWith("CantBeBlockedBy ")) {
|
||||
final String[] k = keyword.split(" ", 2);
|
||||
|
||||
effect = "Mode$ CantBlockBy | ValidAttacker$ Creature.Self | ValidBlocker$ " + k[1]
|
||||
+ " | Description$ CARDNAME can't be blocked " + getTextForKwCantBeBlockedByType(keyword);
|
||||
}
|
||||
|
||||
if (effect != null) {
|
||||
@@ -4277,4 +4285,110 @@ public class CardFactoryUtil {
|
||||
return as;
|
||||
// ETBReplacementMove(sa.getHostCard(), null));
|
||||
}
|
||||
|
||||
private static String getTextForKwCantBeBlockedByType(final String keyword) {
|
||||
boolean negative = true;
|
||||
final List<String> subs = Lists.newArrayList(TextUtil.split(keyword.split(" ", 2)[1], ','));
|
||||
final List<List<String>> subsAnd = Lists.newArrayList();
|
||||
final List<String> orClauses = Lists.newArrayList();
|
||||
for (final String expession : subs) {
|
||||
final List<String> parts = Lists.newArrayList(expession.split("[.+]"));
|
||||
for (int p = 0; p < parts.size(); p++) {
|
||||
final String part = parts.get(p);
|
||||
if (part.equalsIgnoreCase("creature")) {
|
||||
parts.remove(p--);
|
||||
continue;
|
||||
}
|
||||
// based on suppossition that each expression has at least 1 predicate except 'creature'
|
||||
negative &= part.contains("non") || part.contains("without");
|
||||
}
|
||||
subsAnd.add(parts);
|
||||
}
|
||||
|
||||
final boolean allNegative = negative;
|
||||
final String byClause = allNegative ? "except by " : "by ";
|
||||
|
||||
final Function<Pair<Boolean, String>, String> withToString = new Function<Pair<Boolean, String>, String>() {
|
||||
@Override
|
||||
public String apply(Pair<Boolean, String> inp) {
|
||||
boolean useNon = inp.getKey() == allNegative;
|
||||
return (useNon ? "*NO* " : "") + inp.getRight();
|
||||
}
|
||||
};
|
||||
|
||||
for (final List<String> andOperands : subsAnd) {
|
||||
final List<Pair<Boolean, String>> prependedAdjectives = Lists.newArrayList();
|
||||
final List<Pair<Boolean, String>> postponedAdjectives = Lists.newArrayList();
|
||||
String creatures = null;
|
||||
|
||||
for (String part : andOperands) {
|
||||
boolean positive = true;
|
||||
if (part.startsWith("non")) {
|
||||
part = part.substring(3);
|
||||
positive = false;
|
||||
}
|
||||
if (part.startsWith("with")) {
|
||||
positive = !part.startsWith("without");
|
||||
postponedAdjectives.add(Pair.of(positive, part.substring(positive ? 4 : 7)));
|
||||
} else if (part.startsWith("powerLEX")) {// Kraken of the Straits
|
||||
postponedAdjectives.add(Pair.of(true, "power less than the number of islands you control"));
|
||||
} else if (part.startsWith("power")) {
|
||||
int kwLength = 5;
|
||||
String opName = Expressions.operatorName(part.substring(kwLength, kwLength + 2));
|
||||
String operand = part.substring(kwLength + 2);
|
||||
postponedAdjectives.add(Pair.of(true, "power" + opName + operand));
|
||||
} else if (CardType.isACreatureType(part)) {
|
||||
if (creatures != null && CardType.isACreatureType(creatures)) { // e.g. Kor Castigator
|
||||
creatures = StringUtils.capitalize(Lang.getPlural(part)) + creatures;
|
||||
} else {
|
||||
creatures = StringUtils.capitalize(Lang.getPlural(part)) + (creatures == null ? "" : " or " + creatures);
|
||||
}
|
||||
// Kor Castigator and other similar creatures with composite subtype Eldrazi Scion in their text
|
||||
creatures = TextUtil.fastReplace(creatures, "Scions or Eldrazis", "Eldrazi Scions");
|
||||
} else {
|
||||
prependedAdjectives.add(Pair.of(positive, part.toLowerCase()));
|
||||
}
|
||||
}
|
||||
|
||||
StringBuilder sbShort = new StringBuilder();
|
||||
if (allNegative) {
|
||||
boolean isFirst = true;
|
||||
for (Pair<Boolean, String> pre : prependedAdjectives) {
|
||||
if (isFirst) isFirst = false;
|
||||
else sbShort.append(" and/or ");
|
||||
|
||||
boolean useNon = pre.getKey() == allNegative;
|
||||
if (useNon) sbShort.append("non-");
|
||||
sbShort.append(pre.getValue()).append(" ").append(creatures == null ? "creatures" : creatures);
|
||||
}
|
||||
if (prependedAdjectives.isEmpty())
|
||||
sbShort.append(creatures == null ? "creatures" : creatures);
|
||||
|
||||
if (!postponedAdjectives.isEmpty()) {
|
||||
if (!prependedAdjectives.isEmpty()) {
|
||||
sbShort.append(" and/or creatures");
|
||||
}
|
||||
|
||||
sbShort.append(" with ");
|
||||
sbShort.append(Lang.joinHomogenous(postponedAdjectives, withToString, allNegative ? "or" : "and"));
|
||||
}
|
||||
|
||||
} else {
|
||||
for (Pair<Boolean, String> pre : prependedAdjectives) {
|
||||
boolean useNon = pre.getKey() == allNegative;
|
||||
if (useNon) sbShort.append("non-");
|
||||
sbShort.append(pre.getValue()).append(" ");
|
||||
}
|
||||
sbShort.append(creatures == null ? "creatures" : creatures);
|
||||
|
||||
if (!postponedAdjectives.isEmpty()) {
|
||||
sbShort.append(" with ");
|
||||
sbShort.append(Lang.joinHomogenous(postponedAdjectives, withToString, allNegative ? "or" : "and"));
|
||||
}
|
||||
|
||||
}
|
||||
orClauses.add(sbShort.toString());
|
||||
}
|
||||
return byClause + StringUtils.join(orClauses, " or ") + ".";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1005,34 +1005,6 @@ public class CombatUtil {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO remove it later to replace it with CantBlockBy above
|
||||
for (KeywordInterface inst1 : attacker.getKeywords()) {
|
||||
String k = inst1.getOriginal();
|
||||
if (k.startsWith("CantBeBlockedBy ")) {
|
||||
final String[] n = k.split(" ", 2);
|
||||
final String[] restrictions = n[1].split(",");
|
||||
if (blocker.isValid(restrictions, attacker.getController(), attacker, null)) {
|
||||
boolean stillblock = false;
|
||||
//Dragon Hunter check
|
||||
if (n[1].contains("withoutReach") && blocker.hasStartOfKeyword("IfReach")) {
|
||||
for (KeywordInterface inst2 : blocker.getKeywords()) {
|
||||
String k2 = inst2.getOriginal();
|
||||
if (k2.startsWith("IfReach")) {
|
||||
String n2[] = k2.split(":");
|
||||
if (attacker.getType().hasCreatureType(n2[1])) {
|
||||
stillblock = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!stillblock) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (KeywordInterface inst : blocker.getKeywords()) {
|
||||
String keyword = inst.getOriginal();
|
||||
if (keyword.startsWith("CantBlockCardUID")) {
|
||||
|
||||
Reference in New Issue
Block a user