mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 11:18:01 +00:00
CantBeBlockedByAmount + expression used to specify number or creatures that can block given attacker
This commit is contained in:
@@ -42,7 +42,6 @@ import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import forge.CardPredicates.Presets;
|
||||
import forge.Constant.CardTypes;
|
||||
import forge.card.CardCharacteristics;
|
||||
import forge.card.CardDb;
|
||||
import forge.card.CardRarity;
|
||||
@@ -2128,106 +2127,10 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
continue;
|
||||
} else if (keyword.startsWith("CantBeBlockedBy")) {
|
||||
sbLong.append(this.getName()).append(" can't be blocked ");
|
||||
|
||||
boolean negative = true;
|
||||
List<String> subs = Lists.newArrayList(TextUtil.split(keyword.split(" ", 2)[1], ','));
|
||||
List<List<String>> subsAnd = Lists.newArrayList();
|
||||
List<String> orClauses = new ArrayList<String>();
|
||||
for( int iOr = 0; iOr < subs.size(); iOr++ ) {
|
||||
String expession = subs.get(iOr);
|
||||
List<String> parts = Lists.newArrayList(expession.split("[.+]"));
|
||||
for(int p = 0; p < parts.size(); p++) {
|
||||
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;
|
||||
if( allNegative ) sbLong.append("except ");
|
||||
sbLong.append("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().booleanValue() == allNegative;
|
||||
return (useNon ? "*NO* " : "" ) + inp.getRight();
|
||||
}
|
||||
};
|
||||
|
||||
for( int iOr = 0; iOr < subsAnd.size(); iOr++ ) {
|
||||
List<String> andOperands = subsAnd.get(iOr);
|
||||
List<Pair<Boolean, String>> prependedAdjectives = Lists.newArrayList();
|
||||
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("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 ( forge.card.CardType.isACreatureType(part)) {
|
||||
creatures = StringUtils.capitalize(Lang.getPlural(part)) + ( creatures == null ? "" : " or " + creatures );
|
||||
} 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().booleanValue() == 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().booleanValue() == 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());
|
||||
}
|
||||
|
||||
sbLong.append(StringUtils.join(orClauses, " or "));
|
||||
if( keyword.startsWith("CantBeBlockedByAmount"))
|
||||
sbLong.append(getTextForKwCantBeBlockedByAmount(keyword));
|
||||
else
|
||||
sbLong.append(getTextForKwCantBeBlockedByType(keyword));
|
||||
}
|
||||
|
||||
else {
|
||||
@@ -2252,6 +2155,114 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private String getTextForKwCantBeBlockedByAmount(String keyword) {
|
||||
String restriction = keyword.split(" ", 2)[1];
|
||||
boolean isLT = "LT".equals(restriction.substring(0,2));
|
||||
final String byClause = isLT ? "except by " : "by more than";
|
||||
int cnt = Integer.parseInt(restriction.substring(2));
|
||||
return byClause + Lang.nounWithNumeral(cnt, isLT ? "or more creature" : "creature");
|
||||
}
|
||||
|
||||
private String getTextForKwCantBeBlockedByType(String keyword) {
|
||||
boolean negative = true;
|
||||
List<String> subs = Lists.newArrayList(TextUtil.split(keyword.split(" ", 2)[1], ','));
|
||||
List<List<String>> subsAnd = Lists.newArrayList();
|
||||
List<String> orClauses = new ArrayList<String>();
|
||||
for( int iOr = 0; iOr < subs.size(); iOr++ ) {
|
||||
String expession = subs.get(iOr);
|
||||
List<String> parts = Lists.newArrayList(expession.split("[.+]"));
|
||||
for(int p = 0; p < parts.size(); p++) {
|
||||
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().booleanValue() == allNegative;
|
||||
return (useNon ? "*NO* " : "" ) + inp.getRight();
|
||||
}
|
||||
};
|
||||
|
||||
for( int iOr = 0; iOr < subsAnd.size(); iOr++ ) {
|
||||
List<String> andOperands = subsAnd.get(iOr);
|
||||
List<Pair<Boolean, String>> prependedAdjectives = Lists.newArrayList();
|
||||
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("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 ( forge.card.CardType.isACreatureType(part)) {
|
||||
creatures = StringUtils.capitalize(Lang.getPlural(part)) + ( creatures == null ? "" : " or " + creatures );
|
||||
} 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().booleanValue() == 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().booleanValue() == 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
|
||||
/**
|
||||
* <p>
|
||||
@@ -5141,7 +5152,7 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
* @return a boolean.
|
||||
*/
|
||||
public final boolean hasStartOfUnHiddenKeyword(final String keyword) {
|
||||
final ArrayList<String> a = this.getUnhiddenKeyword();
|
||||
final List<String> a = this.getUnhiddenKeyword();
|
||||
for (int i = 0; i < a.size(); i++) {
|
||||
if (a.get(i).toString().startsWith(keyword)) {
|
||||
return true;
|
||||
|
||||
@@ -1047,9 +1047,8 @@ public class AttachAi extends SpellAbilityAi {
|
||||
final boolean evasive = (keyword.equals("Unblockable") || keyword.equals("Fear")
|
||||
|| keyword.equals("Intimidate") || keyword.equals("Shadow")
|
||||
|| keyword.equals("Flying") || keyword.equals("Horsemanship")
|
||||
|| keyword.endsWith("walk") || keyword.equals("CARDNAME can't be blocked except by Walls.")
|
||||
|| keyword.equals("All creatures able to block CARDNAME do so.")
|
||||
|| keyword.equals("CARDNAME can't be blocked by more than one creature."));
|
||||
|| keyword.endsWith("walk") || keyword.startsWith("CantBeBlockedBy")
|
||||
|| keyword.equals("All creatures able to block CARDNAME do so."));
|
||||
// give evasive keywords to creatures that can attack and deal damage
|
||||
if (evasive) {
|
||||
if (card.getNetCombatDamage() + powerBonus <= 0
|
||||
|
||||
@@ -167,8 +167,7 @@ public abstract class PumpAiBase extends SpellAbilityAi {
|
||||
|
||||
final boolean evasive = (keyword.endsWith("Unblockable") || keyword.endsWith("Fear")
|
||||
|| keyword.endsWith("Intimidate") || keyword.endsWith("Shadow")
|
||||
|| keyword.contains("CantBeBlockedBy") || keyword.endsWith("CARDNAME can't be blocked except by Walls.")
|
||||
|| keyword.endsWith("CARDNAME can't be blocked except by two or more creatures."));
|
||||
|| keyword.startsWith("CantBeBlockedBy"));
|
||||
final boolean combatRelevant = (keyword.endsWith("First Strike") || keyword.contains("Bushido"));
|
||||
// give evasive keywords to creatures that can or do attack
|
||||
if (evasive) {
|
||||
|
||||
@@ -951,9 +951,7 @@ public class AiAttackController {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (numberOfPossibleBlockers > 1
|
||||
|| (numberOfPossibleBlockers == 1
|
||||
&& !attacker.hasKeyword("CARDNAME can't be blocked except by two or more creatures."))) {
|
||||
if (numberOfPossibleBlockers > 1 || (numberOfPossibleBlockers == 1 && CombatUtil.canAttackerBeBlockedWithAmount(attacker, 1))) {
|
||||
canBeBlocked = true;
|
||||
}
|
||||
/*System.out.println(attacker + " canBeKilledByOne: " + canBeKilledByOne + " canKillAll: "
|
||||
|
||||
@@ -343,7 +343,7 @@ public class ComputerUtilBlock {
|
||||
|
||||
for (final Card attacker : ComputerUtilBlock.getAttackersLeft()) {
|
||||
|
||||
if (attacker.hasKeyword("CARDNAME can't be blocked except by two or more creatures.")) {
|
||||
if (attacker.hasStartOfKeyword("CantBeBlockedByAmount LT")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -405,7 +405,7 @@ public class ComputerUtilBlock {
|
||||
* a {@link forge.game.phase.Combat} object.
|
||||
* @return a {@link forge.game.phase.Combat} object.
|
||||
*/
|
||||
static final Predicate<Card> rampagesOrNeedsManyToBlock = Predicates.or(CardPredicates.containsKeyword("Rampage"), CardPredicates.containsKeyword("CARDNAME can't be blocked by more than one creature."));
|
||||
static final Predicate<Card> rampagesOrNeedsManyToBlock = Predicates.or(CardPredicates.containsKeyword("Rampage"), CardPredicates.containsKeyword("CantBeBlockedByAmount GT"));
|
||||
|
||||
private static Combat makeGangBlocks(final Player ai, final Combat combat) {
|
||||
List<Card> currentAttackers = CardLists.filter(ComputerUtilBlock.getAttackersLeft(), Predicates.not(rampagesOrNeedsManyToBlock));
|
||||
@@ -537,7 +537,7 @@ public class ComputerUtilBlock {
|
||||
|
||||
for (final Card attacker : ComputerUtilBlock.getAttackersLeft()) {
|
||||
|
||||
if (attacker.hasKeyword("CARDNAME can't be blocked except by two or more creatures.")) {
|
||||
if (attacker.hasStartOfKeyword("CantBeBlockedByAmount LT")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -579,8 +579,7 @@ public class ComputerUtilBlock {
|
||||
|
||||
Card attacker = attackers.get(0);
|
||||
|
||||
if (attacker.hasKeyword("CARDNAME can't be blocked except by two or more creatures.")
|
||||
|| attacker.hasKeyword("You may have CARDNAME assign its combat damage as though it weren't blocked.")) {
|
||||
if (attacker.hasStartOfKeyword("CantBeBlockedByAmount LT") || attacker.hasKeyword("You may have CARDNAME assign its combat damage as though it weren't blocked.")) {
|
||||
attackers.remove(0);
|
||||
return makeChumpBlocks(ai, combat, attackers);
|
||||
}
|
||||
@@ -643,8 +642,7 @@ public class ComputerUtilBlock {
|
||||
|
||||
for (final Card attacker : tramplingAttackers) {
|
||||
|
||||
if ((attacker.hasKeyword("CARDNAME can't be blocked except by two or more creatures.")
|
||||
&& !combat.isBlocked(attacker))
|
||||
if ((attacker.hasStartOfKeyword("CantBeBlockedByAmount LT") && !combat.isBlocked(attacker))
|
||||
|| attacker.hasKeyword("You may have CARDNAME assign its combat damage as though it weren't blocked.")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -417,11 +417,8 @@ public class ComputerUtilCard {
|
||||
if (c.hasKeyword("Intimidate")) {
|
||||
value += power * 6;
|
||||
}
|
||||
if (c.hasStartOfKeyword("CARDNAME can't be blocked except by")) {
|
||||
value += power * 5;
|
||||
}
|
||||
if (c.hasStartOfKeyword("CARDNAME can't be blocked by")) {
|
||||
value += power * 2;
|
||||
if (c.hasStartOfKeyword("CantBeBlockedBy")) {
|
||||
value += power * 3;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import com.esotericsoftware.minlog.Log;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import forge.Card;
|
||||
import forge.CardLists;
|
||||
@@ -50,6 +51,8 @@ import forge.game.combat.AttackingBand;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerController.ManaPaymentPurpose;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.util.Expressions;
|
||||
import forge.util.TextUtil;
|
||||
|
||||
|
||||
/**
|
||||
@@ -179,8 +182,7 @@ public class CombatUtil {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (attacker.hasKeyword("CARDNAME can't be blocked by more than one creature.") &&
|
||||
!combat.getBlockers(attacker).isEmpty()) {
|
||||
if (attacker.hasStartOfKeyword("CantBeBlockedByAmount GT") && !combat.getBlockers(attacker).isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
return CombatUtil.canBeBlocked(attacker);
|
||||
@@ -321,24 +323,14 @@ public class CombatUtil {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (attacker.hasKeyword("CARDNAME can't be blocked except by two or more creatures.")) {
|
||||
int blocks = 0;
|
||||
for (final Card blocker : blockers) {
|
||||
if (CombatUtil.canBlock(attacker, blocker)) {
|
||||
blocks += 1;
|
||||
if (blocks > 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (final Card blocker : blockers) {
|
||||
if (CombatUtil.canBlock(attacker, blocker)) {
|
||||
return true;
|
||||
}
|
||||
int blocks = 0;
|
||||
for (final Card blocker : blockers) {
|
||||
if (CombatUtil.canBlock(attacker, blocker)) {
|
||||
blocks++;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
return canAttackerBeBlockedWithAmount(attacker, blocks);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -356,11 +348,12 @@ public class CombatUtil {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (attacker.hasKeyword("CARDNAME can't be blocked except by two or more creatures.")) {
|
||||
if (attacker.hasKeyword("CantBeBlockedByAmount LT2")) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
return 1;
|
||||
} else if (attacker.hasKeyword("CantBeBlockedByAmount LT3")) {
|
||||
return 3;
|
||||
} else
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Has the human player chosen all mandatory blocks?
|
||||
@@ -390,7 +383,7 @@ public class CombatUtil {
|
||||
for (final Card attacker : attackers) {
|
||||
if (CombatUtil.canBlock(attacker, blocker, combat)) {
|
||||
boolean must = true;
|
||||
if (attacker.hasKeyword("CARDNAME can't be blocked except by two or more creatures.")) {
|
||||
if (attacker.hasStartOfKeyword("CantBeBlockedByAmount LT")) {
|
||||
final List<Card> possibleBlockers = CardLists.filter(defending.getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.CREATURES);
|
||||
possibleBlockers.remove(blocker);
|
||||
if (!CombatUtil.canBeBlocked(attacker, possibleBlockers)) {
|
||||
@@ -406,11 +399,9 @@ public class CombatUtil {
|
||||
}
|
||||
|
||||
for (final Card attacker : attackers) {
|
||||
// don't accept one blocker for attackers with this keyword
|
||||
if (attacker.hasKeyword("CARDNAME can't be blocked except by two or more creatures.")
|
||||
&& (combat.getBlockers(attacker).size() == 1)) {
|
||||
// don't accept blocker amount for attackers with keyword defining valid blockers amount
|
||||
if (!canAttackerBeBlockedWithAmount(attacker, combat.getBlockers(attacker).size()))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -497,7 +488,7 @@ public class CombatUtil {
|
||||
for (final Card attacker : attackersWithLure) {
|
||||
if (CombatUtil.canBeBlocked(attacker, combat) && CombatUtil.canBlock(attacker, blocker)) {
|
||||
boolean canBe = true;
|
||||
if (attacker.hasKeyword("CARDNAME can't be blocked except by two or more creatures.")) {
|
||||
if (attacker.hasStartOfKeyword("CantBeBlockedByAmount LT")) {
|
||||
final List<Card> blockers = combat.getDefenderPlayerByAttacker(attacker).getCreaturesInPlay();
|
||||
blockers.remove(blocker);
|
||||
if (!CombatUtil.canBeBlocked(attacker, blockers)) {
|
||||
@@ -515,7 +506,7 @@ public class CombatUtil {
|
||||
if (CombatUtil.canBeBlocked(attacker, combat) && CombatUtil.canBlock(attacker, blocker)
|
||||
&& combat.isAttacking(attacker)) {
|
||||
boolean canBe = true;
|
||||
if (attacker.hasKeyword("CARDNAME can't be blocked except by two or more creatures.")) {
|
||||
if (attacker.hasStartOfKeyword("CantBeBlockedByAmount LT")) {
|
||||
final List<Card> blockers = combat.getDefenderPlayerByAttacker(attacker).getCreaturesInPlay();
|
||||
blockers.remove(blocker);
|
||||
if (!CombatUtil.canBeBlocked(attacker, blockers)) {
|
||||
@@ -645,23 +636,13 @@ public class CombatUtil {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (attacker.hasKeyword("Creatures with power less than CARDNAME's power can't block it.")
|
||||
&& (attacker.getNetAttack() > blocker.getNetAttack())) {
|
||||
return false;
|
||||
}
|
||||
if ((blocker.getNetAttack() > attacker.getNetAttack())
|
||||
&& blocker.hasKeyword("CARDNAME can't be blocked by creatures "
|
||||
+ "with power greater than CARDNAME's power.")) {
|
||||
return false;
|
||||
}
|
||||
if ((blocker.getNetAttack() >= attacker.getNetDefense())
|
||||
&& blocker.hasKeyword("CARDNAME can't be blocked by creatures with "
|
||||
+ "power equal to or greater than CARDNAME's toughness.")) {
|
||||
if (attacker.hasKeyword("Creatures with power less than CARDNAME's power can't block it.") && attacker.getNetAttack() > blocker.getNetAttack()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (attacker.hasStartOfKeyword("CantBeBlockedBy")) {
|
||||
final int keywordPosition = attacker.getKeywordPosition("CantBeBlockedBy");
|
||||
|
||||
if (attacker.hasStartOfKeyword("CantBeBlockedBy ")) {
|
||||
final int keywordPosition = attacker.getKeywordPosition("CantBeBlockedBy ");
|
||||
final String parse = attacker.getKeyword().get(keywordPosition).toString();
|
||||
final String[] k = parse.split(" ", 2);
|
||||
final String[] restrictions = k[1].split(",");
|
||||
@@ -684,29 +665,20 @@ public class CombatUtil {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (attacker.hasKeyword("Flying")
|
||||
|| attacker.hasKeyword("CARDNAME can't be blocked except by creatures with flying or reach.")) {
|
||||
if (!blocker.hasKeyword("Flying") && !blocker.hasKeyword("Reach")) {
|
||||
return false;
|
||||
}
|
||||
if (attacker.hasKeyword("Flying") && !blocker.hasKeyword("Flying") && !blocker.hasKeyword("Reach")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (attacker.hasKeyword("Horsemanship")) {
|
||||
if (!blocker.hasKeyword("Horsemanship")) {
|
||||
return false;
|
||||
}
|
||||
if (attacker.hasKeyword("Horsemanship") && !blocker.hasKeyword("Horsemanship")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (attacker.hasKeyword("Fear")) {
|
||||
if (!blocker.isArtifact() && !blocker.isBlack()) {
|
||||
return false;
|
||||
}
|
||||
if (attacker.hasKeyword("Fear") && !blocker.isArtifact() && !blocker.isBlack()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (attacker.hasKeyword("Intimidate")) {
|
||||
if (!blocker.isArtifact() && !blocker.sharesColorWith(attacker)) {
|
||||
return false;
|
||||
}
|
||||
if (attacker.hasKeyword("Intimidate") && !blocker.isArtifact() && !blocker.sharesColorWith(attacker)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -788,6 +760,22 @@ public class CombatUtil {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean canAttackerBeBlockedWithAmount(Card attacker, int amount) {
|
||||
List<String> restrictions = Lists.newArrayList();
|
||||
for ( String kw : attacker.getKeyword() ) {
|
||||
if ( kw.startsWith("CantBeBlockedByAmount") )
|
||||
restrictions.add(TextUtil.split(kw, ' ', 2)[1]);
|
||||
}
|
||||
for ( String res : restrictions ) {
|
||||
int operand = Integer.parseInt(res.substring(2));
|
||||
String operator = res.substring(0,2);
|
||||
if (Expressions.compare(amount, operator, operand) )
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// can a creature attack if untapped and without summoning sickness?
|
||||
/**
|
||||
|
||||
@@ -73,8 +73,12 @@ public class Lang {
|
||||
else
|
||||
strCount = String.valueOf(cnt) + " ";
|
||||
return strCount + countedForm;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> String nounWithNumeral(int cnt, String noun) {
|
||||
String countedForm = cnt <= 1 ? noun : getPlural(noun);
|
||||
return getNumeral(cnt) + " " + countedForm;
|
||||
}
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
* @param name
|
||||
@@ -96,4 +100,22 @@ public class Lang {
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
public final static String[] numbers0 = new String[] {
|
||||
"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
|
||||
"ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eightteen", "nineteen" };
|
||||
public final static String[] numbers20 = new String[] {"twenty", "thirty", "fourty", "fifty", "sixty", "seventy", "eighty", "ninety" };
|
||||
|
||||
public static String getNumeral(int n) {
|
||||
String prefix = n < 0 ? "minus " : "";
|
||||
n = Math.abs(n);
|
||||
if ( n >= 0 && n < 20 )
|
||||
return prefix + numbers0[n];
|
||||
if ( n < 100 ) {
|
||||
int n1 = n % 10;
|
||||
String ones = n1 == 0 ? "" : numbers0[n1];
|
||||
return prefix + numbers20[(n / 10) - 2] + " " + ones;
|
||||
}
|
||||
return Integer.toString(n);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user