CardType: sanisfySubtypes each time its changed, moved shareTypeWith functions into CardType

This commit is contained in:
Hans Mackowiak
2020-10-03 10:04:10 +02:00
parent ed17ef57e1
commit e281f1e5ec
11 changed files with 155 additions and 188 deletions

View File

@@ -52,6 +52,8 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
public static final CardTypeView EMPTY = new CardType(); public static final CardTypeView EMPTY = new CardType();
public static final String AllCreatureTypes = "AllCreatureTypes";
public enum CoreType { public enum CoreType {
Artifact(true), Artifact(true),
Conspiracy(false), Conspiracy(false),
@@ -152,6 +154,7 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
changed = true; changed = true;
} }
} }
sanisfySubtypes();
return changed; return changed;
} }
public boolean addAll(final CardType type) { public boolean addAll(final CardType type) {
@@ -159,6 +162,7 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
if (coreTypes.addAll(type.coreTypes)) { changed = true; } if (coreTypes.addAll(type.coreTypes)) { changed = true; }
if (supertypes.addAll(type.supertypes)) { changed = true; } if (supertypes.addAll(type.supertypes)) { changed = true; }
if (subtypes.addAll(type.subtypes)) { changed = true; } if (subtypes.addAll(type.subtypes)) { changed = true; }
sanisfySubtypes();
return changed; return changed;
} }
public boolean addAll(final CardTypeView type) { public boolean addAll(final CardTypeView type) {
@@ -166,6 +170,7 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
if (Iterables.addAll(coreTypes, type.getCoreTypes())) { changed = true; } if (Iterables.addAll(coreTypes, type.getCoreTypes())) { changed = true; }
if (Iterables.addAll(supertypes, type.getSupertypes())) { changed = true; } if (Iterables.addAll(supertypes, type.getSupertypes())) { changed = true; }
if (Iterables.addAll(subtypes, type.getSubtypes())) { changed = true; } if (Iterables.addAll(subtypes, type.getSubtypes())) { changed = true; }
sanisfySubtypes();
return changed; return changed;
} }
@@ -175,6 +180,7 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
if (supertypes.removeAll(type.supertypes)) { changed = true; } if (supertypes.removeAll(type.supertypes)) { changed = true; }
if (subtypes.removeAll(type.subtypes)) { changed = true; } if (subtypes.removeAll(type.subtypes)) { changed = true; }
if (changed) { if (changed) {
sanisfySubtypes();
calculatedType = null; calculatedType = null;
return true; return true;
} }
@@ -211,6 +217,7 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
} }
if (changed) { if (changed) {
sanisfySubtypes();
calculatedType = null; calculatedType = null;
} }
return changed; return changed;
@@ -223,7 +230,7 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
} }
boolean changed = Iterables.removeIf(subtypes, Predicates.IS_CREATURE_TYPE); boolean changed = Iterables.removeIf(subtypes, Predicates.IS_CREATURE_TYPE);
// need to remove AllCreatureTypes too when setting Creature Type // need to remove AllCreatureTypes too when setting Creature Type
if (subtypes.remove("AllCreatureTypes")) { if (subtypes.remove(AllCreatureTypes)) {
changed = true; changed = true;
} }
subtypes.addAll(ctypes); subtypes.addAll(ctypes);
@@ -252,7 +259,7 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
final Set<String> creatureTypes = Sets.newHashSet(); final Set<String> creatureTypes = Sets.newHashSet();
if (isCreature() || isTribal()) { if (isCreature() || isTribal()) {
for (final String t : subtypes) { for (final String t : subtypes) {
if (isACreatureType(t) || t.equals("AllCreatureTypes")) { if (isACreatureType(t) || t.equals(AllCreatureTypes)) {
creatureTypes.add(t); creatureTypes.add(t);
} }
} }
@@ -302,7 +309,7 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
} }
@Override @Override
public boolean hasSubtype(final String subtype) { public boolean hasSubtype(final String subtype) {
if (isACreatureType(subtype) && subtypes.contains("AllCreatureTypes")) { if (isACreatureType(subtype) && subtypes.contains(AllCreatureTypes)) {
return true; return true;
} }
return subtypes.contains(subtype); return subtypes.contains(subtype);
@@ -315,7 +322,7 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
creatureType = toMixedCase(creatureType); creatureType = toMixedCase(creatureType);
if (!isACreatureType(creatureType)) { return false; } if (!isACreatureType(creatureType)) { return false; }
return subtypes.contains(creatureType) || subtypes.contains("AllCreatureTypes"); return subtypes.contains(creatureType) || subtypes.contains(AllCreatureTypes);
} }
private static String toMixedCase(final String s) { private static String toMixedCase(final String s) {
if (s.isEmpty()) { if (s.isEmpty()) {
@@ -485,7 +492,7 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
if (ct.isRemoveCreatureTypes()) { if (ct.isRemoveCreatureTypes()) {
Iterables.removeIf(newType.subtypes, Predicates.IS_CREATURE_TYPE); Iterables.removeIf(newType.subtypes, Predicates.IS_CREATURE_TYPE);
// need to remove AllCreatureTypes too when removing creature Types // need to remove AllCreatureTypes too when removing creature Types
newType.subtypes.remove("AllCreatureTypes"); newType.subtypes.remove(AllCreatureTypes);
} }
if (ct.isRemoveArtifactTypes()) { if (ct.isRemoveArtifactTypes()) {
Iterables.removeIf(newType.subtypes, Predicates.IS_ARTIFACT_TYPE); Iterables.removeIf(newType.subtypes, Predicates.IS_ARTIFACT_TYPE);
@@ -503,29 +510,33 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
} }
// sanisfy subtypes // sanisfy subtypes
if (newType != null && !newType.subtypes.isEmpty()) { if (newType != null && !newType.subtypes.isEmpty()) {
if (!newType.isCreature() && !newType.isTribal()) { newType.sanisfySubtypes();
Iterables.removeIf(newType.subtypes, Predicates.IS_CREATURE_TYPE);
newType.subtypes.remove("AllCreatureTypes");
}
if (!newType.isLand()) {
Iterables.removeIf(newType.subtypes, Predicates.IS_LAND_TYPE);
}
if (!newType.isArtifact()) {
Iterables.removeIf(newType.subtypes, Predicates.IS_ARTIFACT_TYPE);
}
if (!newType.isEnchantment()) {
Iterables.removeIf(newType.subtypes, Predicates.IS_ENCHANTMENT_TYPE);
}
if (!newType.isInstant() && !newType.isSorcery()) {
Iterables.removeIf(newType.subtypes, Predicates.IS_SPELL_TYPE);
}
if (!newType.isPlaneswalker() && !newType.isEmblem()) {
Iterables.removeIf(newType.subtypes, Predicates.IS_WALKER_TYPE);
}
} }
return newType == null ? this : newType; return newType == null ? this : newType;
} }
public void sanisfySubtypes() {
if (!isCreature() && !isTribal()) {
Iterables.removeIf(subtypes, Predicates.IS_CREATURE_TYPE);
subtypes.remove(AllCreatureTypes);
}
if (!isLand()) {
Iterables.removeIf(subtypes, Predicates.IS_LAND_TYPE);
}
if (!isArtifact()) {
Iterables.removeIf(subtypes, Predicates.IS_ARTIFACT_TYPE);
}
if (!isEnchantment()) {
Iterables.removeIf(subtypes, Predicates.IS_ENCHANTMENT_TYPE);
}
if (!isInstant() && !isSorcery()) {
Iterables.removeIf(subtypes, Predicates.IS_SPELL_TYPE);
}
if (!isPlaneswalker() && !isEmblem()) {
Iterables.removeIf(subtypes, Predicates.IS_WALKER_TYPE);
}
}
@Override @Override
public Iterator<String> iterator() { public Iterator<String> iterator() {
final Iterator<CoreType> coreTypeIterator = coreTypes.iterator(); final Iterator<CoreType> coreTypeIterator = coreTypes.iterator();
@@ -560,7 +571,64 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
return toString().compareTo(o.toString()); return toString().compareTo(o.toString());
} }
public boolean sharesSubtypeWith(final CardType ctOther) { public boolean sharesCreaturetypeWith(final CardTypeView ctOther) {
if (ctOther == null) {
return false;
}
if (this.subtypes.contains(AllCreatureTypes) && ctOther.hasSubtype(AllCreatureTypes)) {
return true;
}
for (final String type : getCreatureTypes()) {
if (ctOther.hasCreatureType(type)) {
return true;
}
}
return false;
}
public boolean sharesLandTypeWith(final CardTypeView ctOther) {
if (ctOther == null) {
return false;
}
for (final String type : getLandTypes()) {
if (ctOther.hasSubtype(type)) {
return true;
}
}
return false;
}
public boolean sharesPermanentTypeWith(final CardTypeView ctOther) {
if (ctOther == null) {
return false;
}
for (final CoreType type : getCoreTypes()) {
if (type.isPermanent && ctOther.hasType(type)) {
return true;
}
}
return false;
}
public boolean sharesCardTypeWith(final CardTypeView ctOther) {
if (ctOther == null) {
return false;
}
for (final CoreType type : getCoreTypes()) {
if (ctOther.hasType(type)) {
return true;
}
}
return false;
}
public boolean sharesSubtypeWith(final CardTypeView ctOther) {
if (ctOther == null) {
return false;
}
for (final String t : ctOther.getSubtypes()) { for (final String t : ctOther.getSubtypes()) {
if (hasSubtype(t)) { if (hasSubtype(t)) {
return true; return true;

View File

@@ -19,6 +19,12 @@ public interface CardTypeView extends Iterable<String>, Serializable {
boolean hasSupertype(Supertype supertype); boolean hasSupertype(Supertype supertype);
boolean hasSubtype(String subtype); boolean hasSubtype(String subtype);
boolean hasCreatureType(String creatureType); boolean hasCreatureType(String creatureType);
public boolean sharesCreaturetypeWith(final CardTypeView ctOther);
public boolean sharesLandTypeWith(final CardTypeView ctOther);
public boolean sharesPermanentTypeWith(final CardTypeView ctOther);
public boolean sharesCardTypeWith(final CardTypeView ctOther);
boolean isPermanent(); boolean isPermanent();
boolean isCreature(); boolean isCreature();
boolean isPlaneswalker(); boolean isPlaneswalker();

View File

@@ -37,6 +37,7 @@ import forge.util.collect.FCollectionView;
import forge.util.Localizer; import forge.util.Localizer;
import forge.util.CardTranslation; import forge.util.CardTranslation;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -1179,9 +1180,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
} }
if (sa.hasParam("FaceDownAddType")) { if (sa.hasParam("FaceDownAddType")) {
for (String type : sa.getParam("FaceDownAddType").split(",")) { c.addType(Arrays.asList(sa.getParam("FaceDownAddType").split(" & ")));
c.addType(type);
}
} }
if (sa.hasParam("FaceDownPower") || sa.hasParam("FaceDownToughness") if (sa.hasParam("FaceDownPower") || sa.hasParam("FaceDownToughness")

View File

@@ -26,7 +26,6 @@ import forge.ImageKeys;
import forge.StaticData; import forge.StaticData;
import forge.card.*; import forge.card.*;
import forge.card.CardDb.SetPreference; import forge.card.CardDb.SetPreference;
import forge.card.CardType.CoreType;
import forge.card.mana.ManaCost; import forge.card.mana.ManaCost;
import forge.card.mana.ManaCostParser; import forge.card.mana.ManaCostParser;
import forge.game.*; import forge.game.*;
@@ -3098,6 +3097,10 @@ public class Card extends GameEntity implements Comparable<Card> {
currentState.addType(type0); currentState.addType(type0);
} }
public final void addType(final Iterable<String> type0) {
currentState.addType(type0);
}
public final void removeType(final CardType.Supertype st) { public final void removeType(final CardType.Supertype st) {
currentState.removeType(st); currentState.removeType(st);
} }
@@ -4601,84 +4604,34 @@ public class Card extends GameEntity implements Comparable<Card> {
if (c1 == null) { if (c1 == null) {
return false; return false;
} }
return getType().sharesCreaturetypeWith(c1.getType());
for (final String type : getType().getCreatureTypes()) {
if (type.equals("AllCreatureTypes") && c1.hasACreatureType()) {
return true;
}
if (c1.getType().hasCreatureType(type)) {
return true;
}
}
return false;
} }
public final boolean sharesLandTypeWith(final Card c1) { public final boolean sharesLandTypeWith(final Card c1) {
if (c1 == null) { if (c1 == null) {
return false; return false;
} }
return getType().sharesLandTypeWith(c1.getType());
for (final String type : getType().getLandTypes()) {
if (c1.getType().hasSubtype(type)) {
return true;
}
}
return false;
} }
public final boolean sharesPermanentTypeWith(final Card c1) { public final boolean sharesPermanentTypeWith(final Card c1) {
if (c1 == null) { if (c1 == null) {
return false; return false;
} }
return getType().sharesPermanentTypeWith(c1.getType());
for (final CoreType type : getType().getCoreTypes()) {
if (type.isPermanent && c1.getType().hasType(type)) {
return true;
}
}
return false;
} }
public final boolean sharesCardTypeWith(final Card c1) { public final boolean sharesCardTypeWith(final Card c1) {
for (final CoreType type : getType().getCoreTypes()) { if (c1 == null) {
if (c1.getType().hasType(type)) { return false;
return true;
}
} }
return false; return getType().sharesCardTypeWith(c1.getType());
}
public final boolean sharesTypeWith(final Card c1) {
for (final String type : getType()) {
if (c1.getType().hasStringType(type)) {
return true;
}
}
return false;
} }
public final boolean sharesControllerWith(final Card c1) { public final boolean sharesControllerWith(final Card c1) {
return c1 != null && getController().equals(c1.getController()); return c1 != null && getController().equals(c1.getController());
} }
public final boolean hasACreatureType() {
for (final String type : getType().getSubtypes()) {
if (forge.card.CardType.isACreatureType(type) || type.equals("AllCreatureTypes")) {
return true;
}
}
return false;
}
public final boolean hasALandType() {
for (final String type : getType().getSubtypes()) {
if (forge.card.CardType.isALandType(type) || forge.card.CardType.isABasicLandType(type)) {
return true;
}
}
return false;
}
public final boolean hasABasicLandType() { public final boolean hasABasicLandType() {
for (final String type : getType().getSubtypes()) { for (final String type : getType().getSubtypes()) {
if (forge.card.CardType.isABasicLandType(type)) { if (forge.card.CardType.isABasicLandType(type)) {

View File

@@ -587,7 +587,7 @@ public class CardFactory {
String shortColors = ""; String shortColors = "";
if (sa.hasParam("AddTypes")) { if (sa.hasParam("AddTypes")) {
types.addAll(Arrays.asList(sa.getParam("AddTypes").split(","))); types.addAll(Arrays.asList(sa.getParam("AddTypes").split(" & ")));
} }
if (sa.hasParam("AddKeywords")) { if (sa.hasParam("AddKeywords")) {
@@ -654,9 +654,7 @@ public class CardFactory {
state.removeType(CardType.Supertype.Legendary); state.removeType(CardType.Supertype.Legendary);
} }
for (final String type : types) { state.addType(types);
state.addType(type);
}
if (creatureTypes != null) { if (creatureTypes != null) {
state.setCreatureTypes(creatureTypes); state.setCreatureTypes(creatureTypes);
@@ -795,7 +793,7 @@ public class CardFactory {
if (sa.hasParam("SetCreatureTypes")) { if (sa.hasParam("SetCreatureTypes")) {
// currently only Changeling and similar should be affected by that // currently only Changeling and similar should be affected by that
// other cards using AddType$ ChosenType should not // other cards using AddType$ ChosenType should not
if (sta.hasParam("AddType") && "AllCreatureTypes".equals(sta.getParam("AddType"))) { if (sta.hasParam("AddType") && CardType.AllCreatureTypes.equals(sta.getParam("AddType"))) {
state.removeStaticAbility(sta); state.removeStaticAbility(sta);
} }
} }

View File

@@ -1116,7 +1116,7 @@ public class CardFactoryUtil {
for (Card card : cards) { for (Card card : cards) {
Iterables.addAll(creatTypes, card.getType().getCreatureTypes()); Iterables.addAll(creatTypes, card.getType().getCreatureTypes());
} }
int n = creatTypes.contains("AllCreatureTypes") ? CardType.getAllCreatureTypes().size() : creatTypes.size(); int n = creatTypes.contains(CardType.AllCreatureTypes) ? CardType.getAllCreatureTypes().size() : creatTypes.size();
return doXMath(n, m, c); return doXMath(n, m, c);
} }
@@ -1198,7 +1198,7 @@ public class CardFactoryUtil {
// Figure out how to count each class separately. // Figure out how to count each class separately.
for (Card card : adventurers) { for (Card card : adventurers) {
Set<String> creatureTypes = card.getType().getCreatureTypes(); Set<String> creatureTypes = card.getType().getCreatureTypes();
boolean anyType = creatureTypes.contains("AllCreatureTypes"); boolean anyType = creatureTypes.contains(CardType.AllCreatureTypes);
creatureTypes.retainAll(partyTypes); creatureTypes.retainAll(partyTypes);
if (anyType || creatureTypes.size() == 4) { if (anyType || creatureTypes.size() == 4) {
@@ -1997,7 +1997,7 @@ public class CardFactoryUtil {
// Remove Duplicated types // Remove Duplicated types
final Set<String> creatureTypes = c.getType().getCreatureTypes(); final Set<String> creatureTypes = c.getType().getCreatureTypes();
for (String creatureType : creatureTypes) { for (String creatureType : creatureTypes) {
if (creatureType.equals("AllCreatureTypes")) { if (creatureType.equals(CardType.AllCreatureTypes)) {
allCreatureType++; allCreatureType++;
} }
else { else {

View File

@@ -116,6 +116,11 @@ public class CardState extends GameObject {
view.updateType(this); view.updateType(this);
} }
} }
public final void addType(Iterable<String> type0) {
if (type.addAll(type0)) {
view.updateType(this);
}
}
public final void setType(final CardType type0) { public final void setType(final CardType type0) {
if (type0 == type) { if (type0 == type) {
// Logic below would incorrectly clear the type if it's the same object. // Logic below would incorrectly clear the type if it's the same object.

View File

@@ -2117,7 +2117,7 @@ public class Player extends GameEntity implements Comparable<Player> {
} }
public final boolean hasProwl(final String type) { public final boolean hasProwl(final String type) {
if (prowl.contains("AllCreatureTypes")) { if (prowl.contains(CardType.AllCreatureTypes)) {
return true; return true;
} }
return prowl.contains(type); return prowl.contains(type);

View File

@@ -3,7 +3,7 @@ ManaCost:2 U
Types:Creature Shapeshifter Rogue Types:Creature Shapeshifter Rogue
PT:0/0 PT:0/0
K:ETBReplacement:Copy:DBCopy:Optional K:ETBReplacement:Copy:DBCopy:Optional
SVar:DBCopy:DB$ Clone | Choices$ Creature.YouCtrl | AddTypes$ Shapeshifter,Rogue | SpellDescription$ You may have CARDNAME enter the battlefield as a copy of a creature you control, except its a Shapeshifter Rogue in addition to its other types. SVar:DBCopy:DB$ Clone | Choices$ Creature.YouCtrl | AddTypes$ Shapeshifter & Rogue | SpellDescription$ You may have CARDNAME enter the battlefield as a copy of a creature you control, except its a Shapeshifter Rogue in addition to its other types.
AlternateMode:Modal AlternateMode:Modal
Oracle:You may have Glasspool Mimic enter the battlefield as a copy of a creature you control, except its a Shapeshifter Rogue in addition to its other types. Oracle:You may have Glasspool Mimic enter the battlefield as a copy of a creature you control, except its a Shapeshifter Rogue in addition to its other types.

View File

@@ -4,6 +4,6 @@ Loyalty:4
Types:Legendary Planeswalker Tezzeret Types:Legendary Planeswalker Tezzeret
A:AB$ Draw | Cost$ AddCounter<1/LOYALTY> | Planeswalker$ True | NumCards$ 1 | Defined$ You | SpellDescription$ Draw a card. A:AB$ Draw | Cost$ AddCounter<1/LOYALTY> | Planeswalker$ True | NumCards$ 1 | Defined$ You | SpellDescription$ Draw a card.
A:AB$ Animate | Cost$ AddCounter<0/LOYALTY> | Planeswalker$ True | ValidTgts$ Artifact.YouCtrl | TgtPrompt$ Select target artifact you control | Power$ 5 | Toughness$ 5 | Types$ Creature | UntilYourNextTurn$ True | SpellDescription$ Until your next turn, target artifact you control becomes a 5/5 creature in addition to its other types. A:AB$ Animate | Cost$ AddCounter<0/LOYALTY> | Planeswalker$ True | ValidTgts$ Artifact.YouCtrl | TgtPrompt$ Select target artifact you control | Power$ 5 | Toughness$ 5 | Types$ Creature | UntilYourNextTurn$ True | SpellDescription$ Until your next turn, target artifact you control becomes a 5/5 creature in addition to its other types.
A:AB$ ChangeZone | Cost$ SubCounter<7/LOYALTY> | Planeswalker$ True | Ultimate$ True | Origin$ Hand | Destination$ Battlefield | ChangeType$ Card | ChangeNum$ X | References$ X | FaceDown$ True | FaceDownPower$ 5 | FaceDownToughness$ 5 | FaceDownAddType$ Artifact,Creature | StackDescription$ SpellDescription | SpellDescription$ Put any number of cards from your hand onto the battlefield face down. They're 5/5 artifact creatures. A:AB$ ChangeZone | Cost$ SubCounter<7/LOYALTY> | Planeswalker$ True | Ultimate$ True | Origin$ Hand | Destination$ Battlefield | ChangeType$ Card | ChangeNum$ X | References$ X | FaceDown$ True | FaceDownPower$ 5 | FaceDownToughness$ 5 | FaceDownAddType$ Artifact & Creature | StackDescription$ SpellDescription | SpellDescription$ Put any number of cards from your hand onto the battlefield face down. They're 5/5 artifact creatures.
SVar:X:Count$InYourHand SVar:X:Count$InYourHand
Oracle:[+1]: Draw a card.\n[0]: Until your next turn, target artifact you control becomes a 5/5 creature in addition to its other types.\n[-7]: Put any number of cards from your hand onto the battlefield face down. They're 5/5 artifact creatures. Oracle:[+1]: Draw a card.\n[0]: Until your next turn, target artifact you control becomes a 5/5 creature in addition to its other types.\n[-7]: Put any number of cards from your hand onto the battlefield face down. They're 5/5 artifact creatures.

View File

@@ -27,11 +27,7 @@ import forge.StaticData;
import forge.achievement.AchievementCollection; import forge.achievement.AchievementCollection;
import forge.ai.GameState; import forge.ai.GameState;
import forge.assets.FSkinProp; import forge.assets.FSkinProp;
import forge.card.CardDb; import forge.card.*;
import forge.card.CardType;
import forge.card.ColorSet;
import forge.card.ICardFace;
import forge.card.MagicColor;
import forge.card.mana.ManaCost; import forge.card.mana.ManaCost;
import forge.card.mana.ManaCostShard; import forge.card.mana.ManaCostShard;
import forge.control.FControlGamePlayback; import forge.control.FControlGamePlayback;
@@ -39,26 +35,11 @@ import forge.deck.CardPool;
import forge.deck.Deck; import forge.deck.Deck;
import forge.deck.DeckSection; import forge.deck.DeckSection;
import forge.events.UiEventNextGameDecision; import forge.events.UiEventNextGameDecision;
import forge.game.Game; import forge.game.*;
import forge.game.GameEntity;
import forge.game.GameEntityView;
import forge.game.GameEntityViewMap;
import forge.game.GameLogEntryType;
import forge.game.GameObject;
import forge.game.GameType;
import forge.game.PlanarDice;
import forge.game.ability.AbilityFactory;
import forge.game.ability.AbilityKey; import forge.game.ability.AbilityKey;
import forge.game.ability.ApiType; import forge.game.ability.ApiType;
import forge.game.card.Card; import forge.game.card.*;
import forge.game.card.CardCollection; import forge.game.card.token.TokenInfo;
import forge.game.card.CardCollectionView;
import forge.game.card.CardFaceView;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CardView;
import forge.game.card.CounterEnumType;
import forge.game.card.CounterType;
import forge.game.combat.Combat; import forge.game.combat.Combat;
import forge.game.combat.CombatUtil; import forge.game.combat.CombatUtil;
import forge.game.cost.Cost; import forge.game.cost.Cost;
@@ -69,20 +50,10 @@ import forge.game.keyword.Keyword;
import forge.game.keyword.KeywordInterface; import forge.game.keyword.KeywordInterface;
import forge.game.mana.Mana; import forge.game.mana.Mana;
import forge.game.mana.ManaConversionMatrix; import forge.game.mana.ManaConversionMatrix;
import forge.game.player.DelayedReveal; import forge.game.player.*;
import forge.game.player.Player;
import forge.game.player.PlayerActionConfirmMode;
import forge.game.player.PlayerController;
import forge.game.player.PlayerView;
import forge.game.replacement.ReplacementEffect; import forge.game.replacement.ReplacementEffect;
import forge.game.replacement.ReplacementLayer; import forge.game.replacement.ReplacementLayer;
import forge.game.spellability.AbilityManaPart; import forge.game.spellability.*;
import forge.game.spellability.AbilitySub;
import forge.game.spellability.OptionalCostValue;
import forge.game.spellability.SpellAbility;
import forge.game.spellability.SpellAbilityStackInstance;
import forge.game.spellability.SpellAbilityView;
import forge.game.spellability.TargetChoices;
import forge.game.trigger.Trigger; import forge.game.trigger.Trigger;
import forge.game.trigger.WrappedAbility; import forge.game.trigger.WrappedAbility;
import forge.game.zone.MagicStack; import forge.game.zone.MagicStack;
@@ -96,19 +67,7 @@ import forge.interfaces.IMacroSystem;
import forge.item.IPaperCard; import forge.item.IPaperCard;
import forge.item.PaperCard; import forge.item.PaperCard;
import forge.match.NextGameDecision; import forge.match.NextGameDecision;
import forge.match.input.Input; import forge.match.input.*;
import forge.match.input.InputAttack;
import forge.match.input.InputBlock;
import forge.match.input.InputConfirm;
import forge.match.input.InputConfirmMulligan;
import forge.match.input.InputLondonMulligan;
import forge.match.input.InputPassPriority;
import forge.match.input.InputPayMana;
import forge.match.input.InputProxy;
import forge.match.input.InputQueue;
import forge.match.input.InputSelectCardsForConvokeOrImprovise;
import forge.match.input.InputSelectCardsFromList;
import forge.match.input.InputSelectEntitiesFromList;
import forge.model.FModel; import forge.model.FModel;
import forge.properties.ForgeConstants; import forge.properties.ForgeConstants;
import forge.properties.ForgePreferences.FPref; import forge.properties.ForgePreferences.FPref;
@@ -1157,17 +1116,20 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
private void sortCreatureTypes(List<String> types) { private void sortCreatureTypes(List<String> types) {
// build map of creature types in player's main deck against the // build map of creature types in player's main deck against the
// occurrences of each // occurrences of each
CardCollection pool = CardLists.filterControlledBy(game.getCardsInGame(), player);
Map<String, Integer> typesInDeck = Maps.newHashMap(); Map<String, Integer> typesInDeck = Maps.newHashMap();
// TODO JAVA 8 use getOrDefault // TODO JAVA 8 use getOrDefault
for (Card c : pool) { for (Card c : player.getAllCards()) {
// Changeling are all creature types, they are not interesting for // Changeling are all creature types, they are not interesting for
// counting creature types // counting creature types
if (c.hasStartOfKeyword(Keyword.CHANGELING.toString())) { if (c.hasStartOfKeyword(Keyword.CHANGELING.toString())) {
continue; continue;
} }
// same is true if it somehow has all creature types
if (c.getType().hasSubtype(CardType.AllCreatureTypes)) {
continue;
}
// ignore cards that does enter the battlefield as clones // ignore cards that does enter the battlefield as clones
boolean isClone = false; boolean isClone = false;
for (ReplacementEffect re : c.getReplacementEffects()) { for (ReplacementEffect re : c.getReplacementEffects()) {
@@ -1180,8 +1142,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
continue; continue;
} }
Set<String> cardCreatureTypes = c.getType().getCreatureTypes(); for (String type : c.getType().getCreatureTypes()) {
for (String type : cardCreatureTypes) {
Integer count = typesInDeck.get(type); Integer count = typesInDeck.get(type);
if (count == null) { if (count == null) {
count = 0; count = 0;
@@ -1193,54 +1154,31 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
if (sa.getApi() != ApiType.Token) { if (sa.getApi() != ApiType.Token) {
continue; continue;
} }
if (sa.hasParam("TokenTypes")) { if (sa.hasParam("TokenScript")) {
for (String var : sa.getParam("TokenTypes").split(",")) { Card protoType = TokenInfo.getProtoType(sa.getParam("TokenScript"), sa);
if (!CardType.isACreatureType(var)) { for (String type : protoType.getType().getCreatureTypes()) {
continue; Integer count = typesInDeck.get(type);
}
Integer count = typesInDeck.get(var);
if (count == null) { if (count == null) {
count = 0; count = 0;
} }
typesInDeck.put(var, count + 1); typesInDeck.put(type, count + 1);
} }
} }
} }
// same for Trigger that does make Tokens // same for Trigger that does make Tokens
for (Trigger t : c.getTriggers()) { for (Trigger t : c.getTriggers()) {
SpellAbility sa = t.getOverridingAbility(); SpellAbility sa = t.ensureAbility();
String sTokenTypes = null;
if (sa != null) { if (sa != null) {
if (sa.getApi() != ApiType.Token || !sa.hasParam("TokenTypes")) { if (sa.hasParam("TokenScript")) {
continue; Card protoType = TokenInfo.getProtoType(sa.getParam("TokenScript"), sa);
for (String type : protoType.getType().getCreatureTypes()) {
Integer count = typesInDeck.get(type);
if (count == null) {
count = 0;
}
typesInDeck.put(type, count + 1);
}
} }
sTokenTypes = sa.getParam("TokenTypes");
} else if (t.hasParam("Execute")) {
String name = t.getParam("Execute");
if (!c.hasSVar(name)) {
continue;
}
Map<String, String> params = AbilityFactory.getMapParams(c.getSVar(name));
if (!params.containsKey("TokenTypes")) {
continue;
}
sTokenTypes = params.get("TokenTypes");
}
if (sTokenTypes == null) {
continue;
}
for (String var : sTokenTypes.split(",")) {
if (!CardType.isACreatureType(var)) {
continue;
}
Integer count = typesInDeck.get(var);
if (count == null) {
count = 0;
}
typesInDeck.put(var, count + 1);
} }
} }
// special rule for Fabricate and Servo // special rule for Fabricate and Servo
@@ -3086,8 +3024,8 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
public void handleLandPlayed(Card land, Zone zone) { public void handleLandPlayed(Card land, Zone zone) {
IGuiGame guiGame = getGui(); IGuiGame guiGame = getGui();
guiGame.handleLandPlayed(land,zone); guiGame.handleLandPlayed(land,zone);
} }
} }