From 244d5bba47b90b9e9c06118acc7b4f489a3d9f2a Mon Sep 17 00:00:00 2001 From: Maxmtg Date: Tue, 15 Aug 2017 21:40:03 +0000 Subject: [PATCH] Moved hasProperty code (it's forge script parsing in fact) out of CardState object to keep the class clean. --- .gitattributes | 1 + .../src/main/java/forge/ai/GameState.java | 1 - .../java/forge/ai/simulation/GameCopier.java | 2 +- .../src/main/java/forge/card/CardType.java | 12 +- .../main/java/forge/card/CardTypeView.java | 3 +- .../src/main/java/forge/game/ForgeScript.java | 152 ++++++++++++++++++ .../src/main/java/forge/game/card/Card.java | 8 +- .../java/forge/game/card/CardFactory.java | 2 +- .../main/java/forge/game/card/CardState.java | 141 +--------------- .../main/java/forge/game/card/CardUtil.java | 2 +- .../ai/simulation/GameSimulatorTest.java | 2 +- 11 files changed, 179 insertions(+), 147 deletions(-) create mode 100644 forge-game/src/main/java/forge/game/ForgeScript.java diff --git a/.gitattributes b/.gitattributes index 02b5ad6b262..a76ea52aafc 100644 --- a/.gitattributes +++ b/.gitattributes @@ -304,6 +304,7 @@ forge-game/src/main/java/forge/GameCommand.java svneol=native#text/plain forge-game/src/main/java/forge/game/CardTraitBase.java -text forge-game/src/main/java/forge/game/CardTraitPredicates.java -text svneol=unset#text/plain forge-game/src/main/java/forge/game/Direction.java -text +forge-game/src/main/java/forge/game/ForgeScript.java -text forge-game/src/main/java/forge/game/Game.java -text forge-game/src/main/java/forge/game/GameAction.java svneol=native#text/plain forge-game/src/main/java/forge/game/GameActionUtil.java svneol=native#text/plain diff --git a/forge-ai/src/main/java/forge/ai/GameState.java b/forge-ai/src/main/java/forge/ai/GameState.java index 6ba2130e49f..e32b050d84d 100644 --- a/forge-ai/src/main/java/forge/ai/GameState.java +++ b/forge-ai/src/main/java/forge/ai/GameState.java @@ -723,7 +723,6 @@ public abstract class GameState { private void setupPlayerState(int life, Map cardTexts, final Player p) { // Lock check static as we setup player state - final Game game = p.getGame(); Map playerCards = new EnumMap(ZoneType.class); for (Entry kv : cardTexts.entrySet()) { diff --git a/forge-ai/src/main/java/forge/ai/simulation/GameCopier.java b/forge-ai/src/main/java/forge/ai/simulation/GameCopier.java index c068d6a90f5..37096760fe4 100644 --- a/forge-ai/src/main/java/forge/ai/simulation/GameCopier.java +++ b/forge-ai/src/main/java/forge/ai/simulation/GameCopier.java @@ -303,7 +303,7 @@ public class GameCopier { newCard.setSemiPermanentToughnessBoost(c.getSemiPermanentToughnessBoost()); newCard.setDamage(c.getDamage()); - newCard.setChangedCardTypes(c.getChangedCardTypes()); + newCard.setChangedCardTypes(c.getChangedCardTypesMap()); newCard.setChangedCardKeywords(c.getChangedCardKeywords()); // TODO: Is this correct? Does it not duplicate keywords from enchantments and such? for (String kw : c.getHiddenExtrinsicKeywords()) diff --git a/forge-core/src/main/java/forge/card/CardType.java b/forge-core/src/main/java/forge/card/CardType.java index f343b3957e5..f27d1d8ac74 100644 --- a/forge-core/src/main/java/forge/card/CardType.java +++ b/forge-core/src/main/java/forge/card/CardType.java @@ -411,11 +411,13 @@ public final class CardType implements Comparable, CardTypeView { } @Override - public CardTypeView getTypeWithChanges(final Map changedCardTypes) { - if (changedCardTypes.isEmpty()) { return this; } + public CardTypeView getTypeWithChanges(final Iterable changedCardTypes) { + CardType newType = null; + // we assume that changes are already correctly ordered (taken from TreeMap.values()) + for (final CardChangedType ct : changedCardTypes) { + if(null == newType) + newType = new CardType(CardType.this); - final CardType newType = new CardType(CardType.this); - for (final CardChangedType ct : changedCardTypes.values()) { if (ct.isRemoveCardTypes()) { newType.coreTypes.clear(); } @@ -441,7 +443,7 @@ public final class CardType implements Comparable, CardTypeView { newType.addAll(ct.getAddType()); } } - return newType; + return newType == null ? this : newType; } @Override diff --git a/forge-core/src/main/java/forge/card/CardTypeView.java b/forge-core/src/main/java/forge/card/CardTypeView.java index 397988d4d5d..0e3464eee87 100644 --- a/forge-core/src/main/java/forge/card/CardTypeView.java +++ b/forge-core/src/main/java/forge/card/CardTypeView.java @@ -1,7 +1,6 @@ package forge.card; import java.io.Serializable; -import java.util.Map; import java.util.Set; import forge.card.CardType.CoreType; @@ -39,5 +38,5 @@ public interface CardTypeView extends Iterable, Serializable { boolean isPhenomenon(); boolean isEmblem(); boolean isTribal(); - CardTypeView getTypeWithChanges(Map changedCardTypes); + CardTypeView getTypeWithChanges(Iterable changedCardTypes); } diff --git a/forge-game/src/main/java/forge/game/ForgeScript.java b/forge-game/src/main/java/forge/game/ForgeScript.java new file mode 100644 index 00000000000..a25e4bb112b --- /dev/null +++ b/forge-game/src/main/java/forge/game/ForgeScript.java @@ -0,0 +1,152 @@ +package forge.game; + +import forge.card.ColorSet; +import forge.card.MagicColor; +import forge.game.ability.AbilityUtils; +import forge.game.card.Card; +import forge.game.card.CardState; +import forge.game.player.Player; +import forge.game.spellability.SpellAbility; +import forge.util.Expressions; + +public class ForgeScript { + + public static boolean cardStateHasProperty(CardState cardState, String property, Player sourceController, + Card source, SpellAbility spellAbility) { + + final boolean isColorlessSource = cardState.getCard().hasKeyword("Colorless Damage Source", cardState); + final ColorSet colors = cardState.getCard().determineColor(cardState); + if (property.contains("White") || property.contains("Blue") || property.contains("Black") + || property.contains("Red") || property.contains("Green")) { + boolean mustHave = !property.startsWith("non"); + boolean withSource = property.endsWith("Source"); + if (withSource && isColorlessSource) { + return false; + } + + final String colorName = property.substring(mustHave ? 0 : 3, property.length() - (withSource ? 6 : 0)); + + int desiredColor = MagicColor.fromName(colorName); + boolean hasColor = colors.hasAnyColor(desiredColor); + if (mustHave != hasColor) + return false; + + } else if (property.contains("Colorless")) { // ... Card is colorless + boolean non = property.startsWith("non"); + boolean withSource = property.endsWith("Source"); + if (non && withSource && isColorlessSource) { + return false; + } + if (non == colors.isColorless()) return false; + + } else if (property.contains("MultiColor")) { + // ... Card is multicolored + if (property.endsWith("Source") && isColorlessSource) + return false; + if (property.startsWith("non") == colors.isMulticolor()) + return false; + + } else if (property.contains("MonoColor")) { // ... Card is monocolored + if (property.endsWith("Source") && isColorlessSource) + return false; + if (property.startsWith("non") == colors.isMonoColor()) + return false; + + } else if (property.startsWith("ChosenColor")) { + if (property.endsWith("Source") && isColorlessSource) + return false; + if (!source.hasChosenColor() || !colors.hasAnyColor(MagicColor.fromName(source.getChosenColor()))) + return false; + + } else if (property.startsWith("AnyChosenColor")) { + if (property.endsWith("Source") && isColorlessSource) + return false; + if (!source.hasChosenColor() + || !colors.hasAnyColor(ColorSet.fromNames(source.getChosenColors()).getColor())) + return false; + + } else if (property.startsWith("non")) { + // ... Other Card types + if (cardState.getTypeWithChanges().hasStringType(property.substring(3))) { + return false; + } + } else if (property.equals("CostsPhyrexianMana")) { + if (!cardState.getManaCost().hasPhyrexian()) { + return false; + } + } else if (property.startsWith("HasSVar")) { + final String svar = property.substring(8); + if (!cardState.hasSVar(svar)) { + return false; + } + } else if (property.equals("ChosenType")) { + if (!cardState.getTypeWithChanges().hasStringType(source.getChosenType())) { + return false; + } + } else if (property.equals("IsNotChosenType")) { + if (cardState.getTypeWithChanges().hasStringType(source.getChosenType())) { + return false; + } + } else if (property.startsWith("HasSubtype")) { + final String subType = property.substring(11); + if (!cardState.getTypeWithChanges().hasSubtype(subType)) { + return false; + } + } else if (property.startsWith("HasNoSubtype")) { + final String subType = property.substring(13); + if (cardState.getTypeWithChanges().hasSubtype(subType)) { + return false; + } + } else if (property.equals("hasActivatedAbilityWithTapCost")) { + for (final SpellAbility sa : cardState.getSpellAbilities()) { + if (sa.isAbility() && (sa.getPayCosts() != null) && sa.getPayCosts().hasTapCost()) { + return true; + } + } + return false; + } else if (property.equals("hasActivatedAbility")) { + for (final SpellAbility sa : cardState.getSpellAbilities()) { + if (sa.isAbility()) { + return true; + } + } + return false; + } else if (property.equals("hasManaAbility")) { + for (final SpellAbility sa : cardState.getSpellAbilities()) { + if (sa.isManaAbility()) { + return true; + } + } + return false; + } else if (property.equals("hasNonManaActivatedAbility")) { + for (final SpellAbility sa : cardState.getSpellAbilities()) { + if (sa.isAbility() && !sa.isManaAbility()) { + return true; + } + } + return false; + } else if (property.startsWith("cmc")) { + int x; + String rhs = property.substring(5); + int y = cardState.getManaCost().getCMC(); + try { + x = Integer.parseInt(rhs); + } catch (final NumberFormatException e) { + x = AbilityUtils.calculateAmount(source, rhs, spellAbility); + } + + if (!Expressions.compare(y, property, x)) { + return false; + } + } else if (!cardState.getTypeWithChanges().hasStringType(property)) { + return false; + } + + return true; + + + + } + + +} diff --git a/forge-game/src/main/java/forge/game/card/Card.java b/forge-game/src/main/java/forge/game/card/Card.java index 359e38293c0..5cb70e0a2c6 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -2709,10 +2709,14 @@ public class Card extends GameEntity implements Comparable { if (changedCardTypes.isEmpty()) { return state.getType(); } - return state.getType().getTypeWithChanges(changedCardTypes); + return state.getType().getTypeWithChanges(getChangedCardTypes()); } - public Map getChangedCardTypes() { + public Iterable getChangedCardTypes() { + return Iterables.unmodifiableIterable(changedCardTypes.values()); + } + + public Map getChangedCardTypesMap() { return Collections.unmodifiableMap(changedCardTypes); } diff --git a/forge-game/src/main/java/forge/game/card/CardFactory.java b/forge-game/src/main/java/forge/game/card/CardFactory.java index 7945c312d83..5d0f04040e6 100644 --- a/forge-game/src/main/java/forge/game/card/CardFactory.java +++ b/forge-game/src/main/java/forge/game/card/CardFactory.java @@ -151,7 +151,7 @@ public class CardFactory { // information about the latest state of the card as it left the battlefield) out.setChangedCardColors(in.getChangedCardColors()); out.setChangedCardKeywords(in.getChangedCardKeywords()); - out.setChangedCardTypes(in.getChangedCardTypes()); + out.setChangedCardTypes(in.getChangedCardTypesMap()); return out; } diff --git a/forge-game/src/main/java/forge/game/card/CardState.java b/forge-game/src/main/java/forge/game/card/CardState.java index f26e15319c6..9b867220525 100644 --- a/forge-game/src/main/java/forge/game/card/CardState.java +++ b/forge-game/src/main/java/forge/game/card/CardState.java @@ -29,19 +29,17 @@ import forge.card.CardEdition; import forge.card.CardRarity; import forge.card.CardType; import forge.card.CardTypeView; -import forge.card.ColorSet; import forge.card.MagicColor; import forge.card.mana.ManaCost; import forge.card.mana.ManaCostParser; +import forge.game.ForgeScript; import forge.game.GameObject; -import forge.game.ability.AbilityUtils; import forge.game.card.CardView.CardStateView; import forge.game.player.Player; import forge.game.replacement.ReplacementEffect; import forge.game.spellability.SpellAbility; import forge.game.staticability.StaticAbility; import forge.game.trigger.Trigger; -import forge.util.Expressions; import forge.util.collect.FCollection; import forge.util.collect.FCollectionView; @@ -377,6 +375,7 @@ public class CardState extends GameObject { view.updateKeywords(c, this); } + public CardRarity getRarity() { return rarity; } @@ -388,6 +387,11 @@ public class CardState extends GameObject { public String getSetCode() { return setCode; } + + public CardTypeView getTypeWithChanges() { + return getType().getTypeWithChanges(card.getChangedCardTypes()); + } + public void setSetCode(String setCode0) { setCode = setCode0; view.updateSetCode(this); @@ -398,136 +402,7 @@ public class CardState extends GameObject { */ @Override public boolean hasProperty(String property, Player sourceController, Card source, SpellAbility spellAbility) { - final boolean isColorlessSource = card.hasKeyword("Colorless Damage Source", this); - final ColorSet colors = card.determineColor(this); - if (property.contains("White") || property.contains("Blue") || property.contains("Black") - || property.contains("Red") || property.contains("Green")) { - boolean mustHave = !property.startsWith("non"); - boolean withSource = property.endsWith("Source"); - if (withSource && isColorlessSource) { - return false; - } - - final String colorName = property.substring(mustHave ? 0 : 3, property.length() - (withSource ? 6 : 0)); - - int desiredColor = MagicColor.fromName(colorName); - boolean hasColor = colors.hasAnyColor(desiredColor); - if (mustHave != hasColor) - return false; - - } else if (property.contains("Colorless")) { // ... Card is colorless - boolean non = property.startsWith("non"); - boolean withSource = property.endsWith("Source"); - if (non && withSource && isColorlessSource) { - return false; - } - if (non == colors.isColorless()) return false; - - } else if (property.contains("MultiColor")) { - // ... Card is multicolored - if (property.endsWith("Source") && isColorlessSource) - return false; - if (property.startsWith("non") == colors.isMulticolor()) - return false; - - } else if (property.contains("MonoColor")) { // ... Card is monocolored - if (property.endsWith("Source") && isColorlessSource) - return false; - if (property.startsWith("non") == colors.isMonoColor()) - return false; - - } else if (property.startsWith("ChosenColor")) { - if (property.endsWith("Source") && isColorlessSource) - return false; - if (!source.hasChosenColor() || !colors.hasAnyColor(MagicColor.fromName(source.getChosenColor()))) - return false; - - } else if (property.startsWith("AnyChosenColor")) { - if (property.endsWith("Source") && isColorlessSource) - return false; - if (!source.hasChosenColor() - || !colors.hasAnyColor(ColorSet.fromNames(source.getChosenColors()).getColor())) - return false; - - } else if (property.startsWith("non")) { - // ... Other Card types - if (card.getType(this).hasStringType(property.substring(3))) { - return false; - } - } else if (property.equals("CostsPhyrexianMana")) { - if (!getManaCost().hasPhyrexian()) { - return false; - } - } else if (property.startsWith("HasSVar")) { - final String svar = property.substring(8); - if (!hasSVar(svar)) { - return false; - } - } else if (property.equals("ChosenType")) { - if (!card.getType(this).hasStringType(source.getChosenType())) { - return false; - } - } else if (property.equals("IsNotChosenType")) { - if (card.getType(this).hasStringType(source.getChosenType())) { - return false; - } - } else if (property.startsWith("HasSubtype")) { - final String subType = property.substring(11); - if (!card.getType(this).hasSubtype(subType)) { - return false; - } - } else if (property.startsWith("HasNoSubtype")) { - final String subType = property.substring(13); - if (card.getType(this).hasSubtype(subType)) { - return false; - } - } else if (property.equals("hasActivatedAbilityWithTapCost")) { - for (final SpellAbility sa : getSpellAbilities()) { - if (sa.isAbility() && (sa.getPayCosts() != null) && sa.getPayCosts().hasTapCost()) { - return true; - } - } - return false; - } else if (property.equals("hasActivatedAbility")) { - for (final SpellAbility sa : getSpellAbilities()) { - if (sa.isAbility()) { - return true; - } - } - return false; - } else if (property.equals("hasManaAbility")) { - for (final SpellAbility sa : getSpellAbilities()) { - if (sa.isManaAbility()) { - return true; - } - } - return false; - } else if (property.equals("hasNonManaActivatedAbility")) { - for (final SpellAbility sa : getSpellAbilities()) { - if (sa.isAbility() && !sa.isManaAbility()) { - return true; - } - } - return false; - } else if (property.startsWith("cmc")) { - int x; - String rhs = property.substring(5); - int y = getManaCost().getCMC(); - try { - x = Integer.parseInt(rhs); - } catch (final NumberFormatException e) { - x = AbilityUtils.calculateAmount(source, rhs, spellAbility); - } - - if (!Expressions.compare(y, property, x)) { - return false; - } - } else if (!card.getType(this).hasStringType(property)) { - return false; - } - - return true; - + return ForgeScript.cardStateHasProperty(this, property, sourceController, source, spellAbility); } diff --git a/forge-game/src/main/java/forge/game/card/CardUtil.java b/forge-game/src/main/java/forge/game/card/CardUtil.java index 928a0f97df4..94c5f0c921a 100644 --- a/forge-game/src/main/java/forge/game/card/CardUtil.java +++ b/forge-game/src/main/java/forge/game/card/CardUtil.java @@ -538,7 +538,7 @@ public final class CardUtil { newCopy.setChangedCardColors(in.getChangedCardColors()); newCopy.setChangedCardKeywords(in.getChangedCardKeywords()); - newCopy.setChangedCardTypes(in.getChangedCardTypes()); + newCopy.setChangedCardTypes(in.getChangedCardTypesMap()); newCopy.setMeldedWith(in.getMeldedWith()); diff --git a/forge-gui-desktop/src/test/java/forge/ai/simulation/GameSimulatorTest.java b/forge-gui-desktop/src/test/java/forge/ai/simulation/GameSimulatorTest.java index df1683340a3..7c36e21e0af 100644 --- a/forge-gui-desktop/src/test/java/forge/ai/simulation/GameSimulatorTest.java +++ b/forge-gui-desktop/src/test/java/forge/ai/simulation/GameSimulatorTest.java @@ -1337,7 +1337,7 @@ public class GameSimulatorTest extends SimulationTestCase { public void testDeathsShadow() { Game game = initAndCreateGame(); Player p = game.getPlayers().get(0); - Player opp = game.getPlayers().get(1); + //Player opp = game.getPlayers().get(1); game.getPhaseHandler().devModeSet(PhaseType.MAIN1, p); addCardToZone("Platinum Angel", p, ZoneType.Battlefield);