diff --git a/res/cardsfolder/a/amrou_kithkin.txt b/res/cardsfolder/a/amrou_kithkin.txt index f02e1cd8caf..a1d5a66f3dd 100644 --- a/res/cardsfolder/a/amrou_kithkin.txt +++ b/res/cardsfolder/a/amrou_kithkin.txt @@ -1,7 +1,6 @@ Name:Amrou Kithkin ManaCost:W W Types:Creature Kithkin -Text:CARDNAME can't be blocked by creatures with power 3 or greater. PT:1/1 K:CantBeBlockedBy Creature.powerGE3 SVar:Picture:http://www.wizards.com/global/images/magic/general/amrou_kithkin.jpg diff --git a/res/cardsfolder/a/amrou_seekers.txt b/res/cardsfolder/a/amrou_seekers.txt index f86797da408..ddfab298142 100644 --- a/res/cardsfolder/a/amrou_seekers.txt +++ b/res/cardsfolder/a/amrou_seekers.txt @@ -1,7 +1,6 @@ Name:Amrou Seekers ManaCost:2 W Types:Creature Kithkin Rebel -Text:CARDNAME can't be blocked except by artifact creatures and/or white creatures. PT:2/2 K:CantBeBlockedBy Creature.nonArtifact+nonWhite SVar:Picture:http://www.wizards.com/global/images/magic/general/amrou_seekers.jpg diff --git a/res/cardsfolder/a/arctic_foxes.txt b/res/cardsfolder/a/arctic_foxes.txt index e1c17d6614b..19f578a4db0 100644 --- a/res/cardsfolder/a/arctic_foxes.txt +++ b/res/cardsfolder/a/arctic_foxes.txt @@ -2,7 +2,7 @@ Name:Arctic Foxes ManaCost:1 W Types:Creature Fox PT:1/1 -S:Mode$ Continuous | Affected$ Card.Self | AddHiddenKeyword$ CantBeBlockedBy Creature.powerGE2 | CheckSVar$ X | SVarCompare$ GE1 | Description$ Creatures with power 2 or greater can't block CARDNAME as long as defending player controls a snow land. +S:Mode$ Continuous | Affected$ Card.Self | AddKeyword$ CantBeBlockedBy Creature.powerGE2 | CheckSVar$ X | SVarCompare$ GE1 | Description$ Creatures with power 2 or greater can't block CARDNAME as long as defending player controls a snow land. SVar:X:Count$Valid Land.Snow+DefenderCtrl SVar:Picture:http://www.wizards.com/global/images/magic/general/arctic_foxes.jpg Oracle:Creatures with power 2 or greater can't block Arctic Foxes as long as defending player controls a snow land. diff --git a/res/cardsfolder/a/argothian_pixies.txt b/res/cardsfolder/a/argothian_pixies.txt index a9aa1355f00..2b0efffdf17 100644 --- a/res/cardsfolder/a/argothian_pixies.txt +++ b/res/cardsfolder/a/argothian_pixies.txt @@ -1,7 +1,7 @@ Name:Argothian Pixies ManaCost:1 G Types:Creature Faerie -Text:Prevent all damage that would be dealt to CARDNAME by artifact creatures.\r\nCARDNAME can't be blocked by artifact creatures. +Text:Prevent all damage that would be dealt to CARDNAME by artifact creatures. PT:2/1 K:PreventAllDamageBy Artifact.Creature K:CantBeBlockedBy Artifact.Creature diff --git a/res/cardsfolder/b/barrenton_cragtreads.txt b/res/cardsfolder/b/barrenton_cragtreads.txt index 5845e39414a..c30642c0df3 100644 --- a/res/cardsfolder/b/barrenton_cragtreads.txt +++ b/res/cardsfolder/b/barrenton_cragtreads.txt @@ -1,7 +1,6 @@ Name:Barrenton Cragtreads ManaCost:2 WU WU Types:Creature Kithkin Scout -Text:Barrenton Cragtreads can't be blocked by red creatures. PT:3/3 K:CantBeBlockedBy Creature.Red SVar:Picture:http://www.wizards.com/global/images/magic/general/barrenton_cragtreads.jpg diff --git a/res/cardsfolder/b/basalt_golem.txt b/res/cardsfolder/b/basalt_golem.txt index 6b919165f19..e9fe743f375 100644 --- a/res/cardsfolder/b/basalt_golem.txt +++ b/res/cardsfolder/b/basalt_golem.txt @@ -1,7 +1,6 @@ Name:Basalt Golem ManaCost:5 Types:Artifact Creature Golem -Text:CARDNAME can't be blocked by artifact creatures. PT:2/4 K:CantBeBlockedBy Artifact.Creature T:Mode$ Blocks | ValidCard$ Creature | ValidBlocked$ Card.Self | DelayedTrigger$ TrigEndCombat | TriggerDescription$ Whenever CARDNAME becomes blocked by a creature, that creature's controller sacrifices it at end of combat. If the player does, he or she puts a 0/2 colorless Wall artifact creature token with defender onto the battlefield. diff --git a/res/cardsfolder/b/bower_passage.txt b/res/cardsfolder/b/bower_passage.txt index d40ddf69175..dbaa1ccbbed 100644 --- a/res/cardsfolder/b/bower_passage.txt +++ b/res/cardsfolder/b/bower_passage.txt @@ -1,7 +1,7 @@ Name:Bower Passage ManaCost:1 G Types:Enchantment -S:Mode$ Continuous | Affected$ Creature.YouCtrl | AddHiddenKeyword$ CantBeBlockedBy Creature.withFlying | Description$ Creatures you control can't be blocked by creatures with flying. +S:Mode$ Continuous | Affected$ Creature.YouCtrl | AddKeyword$ CantBeBlockedBy Creature.withFlying | Description$ Creatures with flying can't block creatures you control. SVar:NonStackingEffect:True SVar:Picture:http://www.wizards.com/global/images/magic/general/bower_passage.jpg Oracle:Creatures with flying can't block creatures you control. diff --git a/res/cardsfolder/c/clockwork_steed.txt b/res/cardsfolder/c/clockwork_steed.txt index 6b233969462..296abdc33a6 100644 --- a/res/cardsfolder/c/clockwork_steed.txt +++ b/res/cardsfolder/c/clockwork_steed.txt @@ -1,7 +1,6 @@ Name:Clockwork Steed ManaCost:4 Types:Artifact Creature Horse -Text:CARDNAME can't be blocked by artifact creatures. PT:0/3 K:etbCounter:P1P0:4 K:CantBeBlockedBy Artifact.Creature diff --git a/res/cardsfolder/c/clockwork_swarm.txt b/res/cardsfolder/c/clockwork_swarm.txt index 19e96bfd720..92aed248354 100644 --- a/res/cardsfolder/c/clockwork_swarm.txt +++ b/res/cardsfolder/c/clockwork_swarm.txt @@ -1,7 +1,6 @@ Name:Clockwork Swarm ManaCost:4 Types:Artifact Creature Insect -Text:CARDNAME can't be blocked by Walls. PT:0/3 K:etbCounter:P1P0:4 K:CantBeBlockedBy Creature.Wall diff --git a/res/cardsfolder/d/deathcult_rogue.txt b/res/cardsfolder/d/deathcult_rogue.txt index fff777fb5e2..2d282a5227b 100644 --- a/res/cardsfolder/d/deathcult_rogue.txt +++ b/res/cardsfolder/d/deathcult_rogue.txt @@ -1,7 +1,6 @@ Name:Deathcult Rogue ManaCost:1 UB UB Types:Creature Human Rogue -Text:CARDNAME can't be blocked except by Rogues. PT:2/2 K:CantBeBlockedBy Creature.nonRogue SVar:Picture:http://www.wizards.com/global/images/magic/general/deathcult_rogue.jpg diff --git a/res/cardsfolder/d/dread_charge.txt b/res/cardsfolder/d/dread_charge.txt index a5d10bf10b8..4c02d8f9612 100644 --- a/res/cardsfolder/d/dread_charge.txt +++ b/res/cardsfolder/d/dread_charge.txt @@ -1,7 +1,7 @@ Name:Dread Charge ManaCost:3 B Types:Sorcery -A:SP$ PumpAll | Cost$ 3 B | ValidCards$ Creature.Black+YouCtrl | KW$ HIDDEN CantBeBlockedBy Creature.nonBlack | SpellDescription$ Until end of turn, black creatures you control can be blocked only by black creatures. +A:SP$ PumpAll | Cost$ 3 B | ValidCards$ Creature.Black+YouCtrl | KW$ CantBeBlockedBy Creature.nonBlack | SpellDescription$ Until end of turn, black creatures you control can be blocked only by black creatures. SVar:RemAIDeck:True SVar:Picture:http://www.wizards.com/global/images/magic/general/dread_charge.jpg Oracle:Until end of turn, black creatures you control can be blocked only by black creatures. diff --git a/res/cardsfolder/d/dread_warlock.txt b/res/cardsfolder/d/dread_warlock.txt index 3951fde3817..cc00e574f95 100644 --- a/res/cardsfolder/d/dread_warlock.txt +++ b/res/cardsfolder/d/dread_warlock.txt @@ -1,7 +1,6 @@ Name:Dread Warlock ManaCost:1 B B Types:Creature Human Wizard -Text:CARDNAME can't be blocked except by black creatures. PT:2/2 K:CantBeBlockedBy Creature.nonBlack SVar:Picture:http://www.wizards.com/global/images/magic/general/dread_warlock.jpg diff --git a/res/cardsfolder/d/dust_corona.txt b/res/cardsfolder/d/dust_corona.txt index 3a3a6bebbf0..11e2f3890b9 100644 --- a/res/cardsfolder/d/dust_corona.txt +++ b/res/cardsfolder/d/dust_corona.txt @@ -3,7 +3,7 @@ ManaCost:R Types:Enchantment Aura K:Enchant creature A:SP$ Attach | Cost$ R | ValidTgts$ Creature | AILogic$ Pump -S:Mode$ Continuous | Affected$ Creature.EnchantedBy | AddPower$ 2 | AddHiddenKeyword$ CantBeBlockedBy Creature.withFlying | Description$ Enchanted creature gets +2/+0 and can't be blocked by creatures with flying. +S:Mode$ Continuous | Affected$ Creature.EnchantedBy | AddPower$ 2 | AddKeyword$ CantBeBlockedBy Creature.withFlying | Description$ Enchanted creature gets +2/+0 and can't be blocked by creatures with flying. SVar:Picture:http://www.wizards.com/global/images/magic/general/dust_corona.jpg Oracle:Enchant creature\nEnchanted creature gets +2/+0 and can't be blocked by creatures with flying. SetInfo:PLC Common \ No newline at end of file diff --git a/res/cardsfolder/g/greater_stone_spirit.txt b/res/cardsfolder/g/greater_stone_spirit.txt index e4408ba6881..834f166a3d8 100644 --- a/res/cardsfolder/g/greater_stone_spirit.txt +++ b/res/cardsfolder/g/greater_stone_spirit.txt @@ -2,7 +2,7 @@ Name:Greater Stone Spirit ManaCost:4 R R Types:Creature Elemental Spirit PT:4/4 -S:Mode$ Continuous | Affected$ Card.Self | AddHiddenKeyword$ CantBeBlockedBy Creature.withFlying | Description$ CARDNAME can't be blocked by creatures with flying. +K:CantBeBlockedBy Creature.withFlying A:AB$ Pump | Cost$ 2 R | ValidTgts$ Creature | NumDef$ 2 | SubAbility$ DBAnimate | SpellDescription$ Until end of turn, target creature gets +0/+2 and gains "R: This creature gets +1/+0 until end of turn." SVar:DBAnimate:DB$ Animate | Defined$ Targeted | Abilities$ Pump SVar:Pump:AB$ Pump | Cost$ R | NumAtt$ 1 | SpellDescription$ This creature gets +1/+0 until end of turn. diff --git a/res/cardsfolder/m/manta_ray.txt b/res/cardsfolder/m/manta_ray.txt index 063caf1f565..15bd68ee283 100644 --- a/res/cardsfolder/m/manta_ray.txt +++ b/res/cardsfolder/m/manta_ray.txt @@ -1,7 +1,6 @@ Name:Manta Ray ManaCost:1 U U Types:Creature Fish -Text:CARDNAME can't be blocked except by blue creatures. PT:3/3 K:CARDNAME can't attack unless defending player controls an Island. K:CantBeBlockedBy Creature.nonBlue diff --git a/res/cardsfolder/o/orchard_spirit.txt b/res/cardsfolder/o/orchard_spirit.txt index 0d4f02561f5..99b05182d89 100644 --- a/res/cardsfolder/o/orchard_spirit.txt +++ b/res/cardsfolder/o/orchard_spirit.txt @@ -1,7 +1,6 @@ Name:Orchard Spirit ManaCost:2 G Types:Creature Spirit -Text:CARDNAME can't be blocked except by creatures with flying or reach. PT:2/2 K:CantBeBlockedBy Creature.withoutFlying+withoutReach SVar:Picture:http://www.wizards.com/global/images/magic/general/orchard_spirit.jpg diff --git a/res/cardsfolder/p/prowling_nightstalker.txt b/res/cardsfolder/p/prowling_nightstalker.txt index 31947e6efd9..007fdb5ee9e 100644 --- a/res/cardsfolder/p/prowling_nightstalker.txt +++ b/res/cardsfolder/p/prowling_nightstalker.txt @@ -1,7 +1,6 @@ Name:Prowling Nightstalker ManaCost:3 B Types:Creature Nightstalker -Text:CARDNAME can't be blocked except by black creatures. PT:2/2 K:CantBeBlockedBy Creature.nonBlack SVar:Picture:http://www.wizards.com/global/images/magic/general/prowling_nightstalker.jpg diff --git a/res/cardsfolder/s/sacred_knight.txt b/res/cardsfolder/s/sacred_knight.txt index edf31b09050..78d209e1cd3 100644 --- a/res/cardsfolder/s/sacred_knight.txt +++ b/res/cardsfolder/s/sacred_knight.txt @@ -1,7 +1,6 @@ Name:Sacred Knight ManaCost:3 W Types:Creature Human Knight -Text:CARDNAME can't be blocked by black and/or red creatures. PT:3/2 K:CantBeBlockedBy Creature.Black,Creature.Red SVar:Picture:http://www.wizards.com/global/images/magic/general/sacred_knight.jpg diff --git a/res/cardsfolder/s/signal_pest.txt b/res/cardsfolder/s/signal_pest.txt index 3dc67f0bad0..0c203408e58 100644 --- a/res/cardsfolder/s/signal_pest.txt +++ b/res/cardsfolder/s/signal_pest.txt @@ -1,7 +1,6 @@ Name:Signal Pest ManaCost:1 Types:Artifact Creature Pest -Text:CARDNAME can't be blocked except by creatures with flying or reach. PT:0/1 K:CantBeBlockedBy Creature.withoutFlying+withoutReach T:Mode$ Attacks | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigBattleCry | TriggerDescription$ Battle cry (Whenever this creature attacks, each other attacking creature gets +1/+0 until end of turn.) diff --git a/res/cardsfolder/s/silhana_ledgewalker.txt b/res/cardsfolder/s/silhana_ledgewalker.txt index 199f087b3fd..d8652ff1230 100644 --- a/res/cardsfolder/s/silhana_ledgewalker.txt +++ b/res/cardsfolder/s/silhana_ledgewalker.txt @@ -1,7 +1,6 @@ Name:Silhana Ledgewalker ManaCost:1 G Types:Creature Elf Rogue -Text:CARDNAME can't be blocked except by creatures with flying. PT:1/1 K:CantBeBlockedBy Creature.withoutFlying K:Hexproof diff --git a/res/cardsfolder/s/skirk_shaman.txt b/res/cardsfolder/s/skirk_shaman.txt index a51bed340fb..194507e413b 100644 --- a/res/cardsfolder/s/skirk_shaman.txt +++ b/res/cardsfolder/s/skirk_shaman.txt @@ -1,7 +1,6 @@ Name:Skirk Shaman ManaCost:1 R R Types:Creature Goblin Shaman -Text:Skirk Shaman can't be blocked except by artifact creatures and/or red creatures. PT:2/2 K:CantBeBlockedBy Creature.nonArtifact+nonRed SVar:Picture:http://resources.wizards.com/magic/cards/plc/en-us/card131011.jpg diff --git a/res/cardsfolder/s/sneaky_homunculus.txt b/res/cardsfolder/s/sneaky_homunculus.txt index 47010b6578f..b32ca883344 100644 --- a/res/cardsfolder/s/sneaky_homunculus.txt +++ b/res/cardsfolder/s/sneaky_homunculus.txt @@ -1,7 +1,6 @@ Name:Sneaky Homunculus ManaCost:1 U Types:Creature Homunculus Illusion -Text:CARDNAME can't block or be blocked by creatures with power 2 or greater. PT:1/1 K:CantBeBlockedBy Creature.powerGE2 K:CantBlock Creature.powerGE2 diff --git a/res/cardsfolder/s/stone_spirit.txt b/res/cardsfolder/s/stone_spirit.txt index 939f2f26612..650eb329d31 100644 --- a/res/cardsfolder/s/stone_spirit.txt +++ b/res/cardsfolder/s/stone_spirit.txt @@ -1,7 +1,6 @@ Name:Stone Spirit ManaCost:4 R Types:Creature Elemental Spirit -Text:CARDNAME can't be blocked by creatures with flying. PT:4/3 K:CantBeBlockedBy Creature.withFlying SVar:Picture:http://www.wizards.com/global/images/magic/general/stone_spirit.jpg diff --git a/res/cardsfolder/s/stromkirk_noble.txt b/res/cardsfolder/s/stromkirk_noble.txt index b069c73fe61..ccf748d5e3d 100644 --- a/res/cardsfolder/s/stromkirk_noble.txt +++ b/res/cardsfolder/s/stromkirk_noble.txt @@ -1,7 +1,6 @@ Name:Stromkirk Noble ManaCost:R Types:Creature Vampire -Text:CARDNAME can't be blocked by Humans. PT:1/1 K:CantBeBlockedBy Creature.Human T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | CombatDamage$ True | Execute$ TrigPutCounter | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, put a +1/+1 counter on it. diff --git a/res/cardsfolder/t/treetop_bracers.txt b/res/cardsfolder/t/treetop_bracers.txt index 5d265283565..137dc84b2ad 100644 --- a/res/cardsfolder/t/treetop_bracers.txt +++ b/res/cardsfolder/t/treetop_bracers.txt @@ -3,7 +3,7 @@ ManaCost:1 G Types:Enchantment Aura K:Enchant creature A:SP$ Attach | Cost$ 1 G | ValidTgts$ Creature | AILogic$ Pump -S:Mode$ Continuous | Affected$ Creature.EnchantedBy | AddPower$ 1 | AddToughness$ 1 | AddHiddenKeyword$ CantBeBlockedBy Creature.withoutFlying | Description$ Enchanted creature gets +1/+1 and can't be blocked except by creatures with flying. +S:Mode$ Continuous | Affected$ Creature.EnchantedBy | AddPower$ 1 | AddToughness$ 1 | AddKeyword$ CantBeBlockedBy Creature.withoutFlying | Description$ Enchanted creature gets +1/+1 and can't be blocked except by creatures with flying. SVar:Picture:http://www.wizards.com/global/images/magic/general/treetop_bracers.jpg Oracle:Enchant creature (Target a creature as you cast this. This card enters the battlefield attached to that creature.)\nEnchanted creature gets +1/+1 and can't be blocked except by creatures with flying. SetInfo:10E Common diff --git a/res/cardsfolder/t/treetop_rangers.txt b/res/cardsfolder/t/treetop_rangers.txt index 29e7b43e3be..626b0d642ac 100644 --- a/res/cardsfolder/t/treetop_rangers.txt +++ b/res/cardsfolder/t/treetop_rangers.txt @@ -1,7 +1,6 @@ Name:Treetop Rangers ManaCost:2 G Types:Creature Elf -Text:CARDNAME can't be blocked except by creatures with flying. PT:2/2 K:CantBeBlockedBy Creature.withoutFlying SVar:Picture:http://www.wizards.com/global/images/magic/general/treetop_rangers.jpg diff --git a/res/cardsfolder/t/treetop_scout.txt b/res/cardsfolder/t/treetop_scout.txt index 12edd49fe14..e51a946b34d 100644 --- a/res/cardsfolder/t/treetop_scout.txt +++ b/res/cardsfolder/t/treetop_scout.txt @@ -1,7 +1,6 @@ Name:Treetop Scout ManaCost:G Types:Creature Elf Scout -Text:CARDNAME can't be blocked except by creatures with flying. PT:1/1 K:CantBeBlockedBy Creature.withoutFlying SVar:Picture:http://www.wizards.com/global/images/magic/general/treetop_scout.jpg diff --git a/res/cardsfolder/v/vindictive_mob.txt b/res/cardsfolder/v/vindictive_mob.txt index da551e1f793..6f8c4a9d5aa 100644 --- a/res/cardsfolder/v/vindictive_mob.txt +++ b/res/cardsfolder/v/vindictive_mob.txt @@ -1,7 +1,6 @@ Name:Vindictive Mob ManaCost:4 B B Types:Creature Human Berserker -Text:CARDNAME can't be blocked by Saprolings. PT:5/5 T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigSac | TriggerDescription$ When CARDNAME enters the battlefield, sacrifice a creature. SVar:TrigSac:AB$Sacrifice | Cost$ 0 | Defined$ You | SacValid$ Creature diff --git a/res/cardsfolder/z/zuo_ci_the_mocking_sage.txt b/res/cardsfolder/z/zuo_ci_the_mocking_sage.txt index 779c97e5296..2f3781de5cc 100644 --- a/res/cardsfolder/z/zuo_ci_the_mocking_sage.txt +++ b/res/cardsfolder/z/zuo_ci_the_mocking_sage.txt @@ -1,7 +1,6 @@ Name:Zuo Ci, the Mocking Sage ManaCost:1 G G Types:Legendary Creature Human Advisor -Text:CARDNAME can't be blocked by creatures with horsemanship. PT:1/2 K:CantBeBlockedBy Creature.withHorsemanship K:Hexproof diff --git a/src/main/java/forge/Card.java b/src/main/java/forge/Card.java index fd22cd11bef..7c6f0125e30 100644 --- a/src/main/java/forge/Card.java +++ b/src/main/java/forge/Card.java @@ -34,11 +34,15 @@ import java.util.concurrent.ConcurrentSkipListMap; import java.util.concurrent.CopyOnWriteArrayList; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Pair; import com.esotericsoftware.minlog.Log; +import com.google.common.base.Function; 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; @@ -2123,30 +2127,107 @@ public class Card extends GameEntity implements Comparable { // keyword parsing takes care of adding a proper description continue; } else if (keyword.startsWith("CantBeBlockedBy")) { - String expression = keyword.split(" ", 2)[1]; - boolean hasNon = expression.contains("non") || expression.contains("without"); - sbLong.append(this.getName()).append(" cannot be blocked "); - if( hasNon ) sbLong.append("except "); - sbLong.append("by "); - String[] parts = TextUtil.split(expression, '.'); - List partsAfterCreatures = new ArrayList(); - for(String part : parts) { - if( part.equalsIgnoreCase("creature")) - continue; - if(part.startsWith("with")) - { - int cutIdx = part.startsWith("without") ? 7 : 4; - partsAfterCreatures.add(StringUtils.capitalize(part.substring(cutIdx))); + sbLong.append(this.getName()).append(" can't be blocked "); + + boolean negative = true; + List subs = Lists.newArrayList(TextUtil.split(keyword.split(" ", 2)[1], ',')); + List> subsAnd = Lists.newArrayList(); + List orClauses = new ArrayList(); + for( int iOr = 0; iOr < subs.size(); iOr++ ) { + String expession = subs.get(iOr); + List 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"); } - else - sbLong.append(part.toLowerCase()).append(" "); + subsAnd.add(parts); + } + + final boolean allNegative = negative; + if( allNegative ) sbLong.append("except "); + sbLong.append("by "); + + final Function, String> withToString = new Function, String>() { + @Override + public String apply(Pair inp) { + boolean useNon = inp.getKey().booleanValue() == allNegative; + return (useNon ? "*NO* " : "" ) + inp.getRight(); + } + }; + + for( int iOr = 0; iOr < subsAnd.size(); iOr++ ) { + List andOperands = subsAnd.get(iOr); + List> prependedAdjectives = Lists.newArrayList(); + List> 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 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 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("creatures"); - if( !partsAfterCreatures.isEmpty() ) { - sbLong.append(" with "); - sbLong.append(Lang.joinHomogenous(partsAfterCreatures, null, hasNon ? "or" : "and")); - } + + sbLong.append(StringUtils.join(orClauses, " or ")); } else { diff --git a/src/main/java/forge/util/Expressions.java b/src/main/java/forge/util/Expressions.java index 6dc6a79c365..592d7f6d008 100644 --- a/src/main/java/forge/util/Expressions.java +++ b/src/main/java/forge/util/Expressions.java @@ -64,4 +64,26 @@ public abstract class Expressions { return false; } + public static String operatorName(final String comp) { + // should this function be somewhere else? + // leftSide COMPARED to rightSide: + if (comp.contains("LT")) { + return " less than "; + } else if (comp.contains("LE")) { + return " less or equal to "; + } else if (comp.contains("EQ")) { + return " equal to "; + } else if (comp.contains("GT")) { + return " greater than "; + } else if (comp.contains("GE")) { + return " greater or equal to "; + } else if (comp.contains("NE")) { + return " not equal to "; + } else if (comp.contains("M2")) { + return " is modulo 2 equal to"; // should not show this to players + } + return " ? "; + } + + } // end class AllZoneUtil diff --git a/src/main/java/forge/util/Lang.java b/src/main/java/forge/util/Lang.java index dc796fcd9ec..bcbfe512e56 100644 --- a/src/main/java/forge/util/Lang.java +++ b/src/main/java/forge/util/Lang.java @@ -61,14 +61,18 @@ public class Lang { return subjects.size() > 1 ? verb : verb + "s"; } + public static String getPlural(String noun) { + return noun + ( noun.endsWith("s") || noun.endsWith("x") ? "es" : "s"); + } + public static String nounWithAmount(int cnt, String noun) { - String suffix = cnt <= 1 ? "" : ( noun.endsWith("s") || noun.endsWith("x") ? "es" : "s"); + String countedForm = cnt <= 1 ? noun : getPlural(noun); final String strCount; if( cnt == 1 ) strCount = startsWithVowel(noun) ? "an " : "a "; else strCount = String.valueOf(cnt) + " "; - return strCount + noun + suffix; + return strCount + countedForm; } /**