package forge; import com.esotericsoftware.minlog.Log; import forge.card.cardFactory.CardFactory; import forge.card.cardFactory.CardFactoryUtil; import forge.card.mana.ManaCost; import forge.card.spellability.Ability_Mana; import forge.card.spellability.Ability_Triggered; import forge.card.spellability.SpellAbility; import forge.card.spellability.Spell_Permanent; import forge.card.staticAbility.StaticAbility; import forge.card.trigger.Trigger; import java.util.*; import java.util.Map.Entry; /** * <p>Card class.</p> * * Can now be used as keys in Tree data structures. The comparison is based * entirely on getUniqueNumber(). * * @author Forge * @version $Id: $ */ public class Card extends MyObservable implements Comparable<Card> { private static int nextUniqueNumber; private int uniqueNumber = nextUniqueNumber++; private long value; private Map<String, Object> triggeringObjects = new TreeMap<String, Object>(); private ArrayList<Trigger> triggers = new ArrayList<Trigger>(); private ArrayList<String> intrinsicAbility = new ArrayList<String>(); private ArrayList<String> staticAbilityStrings = new ArrayList<String>(); private ArrayList<String> intrinsicKeyword = new ArrayList<String>(); private ArrayList<String> extrinsicKeyword = new ArrayList<String>(); private ArrayList<String> otherExtrinsicKeyword = new ArrayList<String>(); private ArrayList<String> HiddenExtrinsicKeyword = new ArrayList<String>(); //Hidden keywords won't be displayed on the card private ArrayList<String> prevIntrinsicKeyword = new ArrayList<String>(); private ArrayList<Card> attached = new ArrayList<Card>(); private ArrayList<Card> equippedBy = new ArrayList<Card>(); //which equipment cards are equipping this card? //equipping size will always be 0 or 1 private ArrayList<Card> equipping = new ArrayList<Card>(); //if this card is of the type equipment, what card is it currently equipping? private ArrayList<Card> enchantedBy = new ArrayList<Card>(); //which auras enchanted this card? //enchanting size will always be 0 or 1 private ArrayList<Card> enchanting = new ArrayList<Card>(); //if this card is an Aura, what card is it enchanting? private ArrayList<String> type = new ArrayList<String>(); private ArrayList<String> prevType = new ArrayList<String>(); private ArrayList<String> ChoicesMade = new ArrayList<String>(); private ArrayList<String> Targets_for_Choices = new ArrayList<String>(); private ArrayList<SpellAbility> spellAbility = new ArrayList<SpellAbility>(); private ArrayList<Ability_Mana> manaAbility = new ArrayList<Ability_Mana>(); private ArrayList<Card_Color> cardColor = new ArrayList<Card_Color>(); private ArrayList<StaticAbility> staticAbilities = new ArrayList<StaticAbility>(); private ArrayList<Object> rememberedObjects = new ArrayList<Object>(); private ArrayList<Card> imprintedCards = new ArrayList<Card>(); private Card championedCard = null; private CardList devouredCards = new CardList(); private Map<Card, Integer> receivedDamageFromThisTurn = new TreeMap<Card, Integer>(); private Map<Card, Integer> dealtDamageToThisTurn = new TreeMap<Card, Integer>(); private Map<Card, Integer> assignedDamageMap = new TreeMap<Card, Integer>(); private boolean unCastable; private boolean drawnThisTurn = false; private boolean tapped; private boolean sickness = true; //summoning sickness private boolean token = false; private boolean copiedToken = false; private boolean copiedSpell = false; private boolean SpellwithChoices = false; private boolean SpellCopyingCard = false; private boolean creatureAttackedThisTurn = false; private boolean creatureAttackedThisCombat = false; private boolean creatureBlockedThisCombat = false; private boolean creatureGotBlockedThisCombat = false; private boolean dealtDmgToHumanThisTurn = false; private boolean dealtDmgToComputerThisTurn = false; private boolean sirenAttackOrDestroy = false; private boolean exaltedBonus = false; private boolean faceDown = false; private boolean sacrificeAtEOT = false; private boolean kicked = false; private boolean evoked = false; private boolean reflectedLand = false; private boolean levelUp = false; private boolean bounceAtUntap = false; private boolean finishedEnteringBF = false; private boolean firstStrike = false; private boolean doubleStrike = false; private boolean flashback = false; private boolean unearth = false; private boolean unearthed; private boolean madness = false; private boolean suspendCast = false; private boolean suspend = false; //for Vanguard / Manapool / Emblems etc. private boolean isImmutable = false; private long timestamp = -1; // permanents on the battlefield private int baseAttack; private int baseDefense; private ArrayList<Card_PT> newPT = new ArrayList<Card_PT>(); // stack of set power/toughness private int baseLoyalty = 0; private String baseAttackString = null; private String baseDefenseString = null; private int damage; private int nShield; // regeneration private int preventNextDamage = 0; private int turnInZone; private int tempAttackBoost = 0; private int tempDefenseBoost = 0; private int semiPermanentAttackBoost = 0; private int semiPermanentDefenseBoost = 0; private int randomPicture = 0; private int X = 0; private int xManaCostPaid = 0; private int xLifePaid = 0; private int multiKickerMagnitude = 0; private int replicateMagnitude = 0; private int sunburstValue = 0; private String colorsPaid = ""; private Player owner = null; private Player controller = null; private String name = ""; private String imageName = ""; private String rarity = ""; private String text = ""; private String manaCost = ""; private String echoCost = ""; private String madnessCost = ""; private String chosenType = ""; private String chosenColor = ""; private String namedCard = ""; private String reflectableMana = ""; private Card cloneOrigin = null; private ArrayList<Card> clones = new ArrayList<Card>(); private Card currentlyCloningCard = null; private Command cloneLeavesPlayCommand = null; private ArrayList<Card> gainControlTargets = new ArrayList<Card>(); private ArrayList<Command> gainControlReleaseCommands = new ArrayList<Command>(); ; private ArrayList<Ability_Triggered> zcTriggers = new ArrayList<Ability_Triggered>(); private ArrayList<Command> turnFaceUpCommandList = new ArrayList<Command>(); private ArrayList<Command> equipCommandList = new ArrayList<Command>(); private ArrayList<Command> unEquipCommandList = new ArrayList<Command>(); private ArrayList<Command> enchantCommandList = new ArrayList<Command>(); private ArrayList<Command> unEnchantCommandList = new ArrayList<Command>(); private ArrayList<Command> untapCommandList = new ArrayList<Command>(); private ArrayList<Command> changeControllerCommandList = new ArrayList<Command>(); private ArrayList<Command> replaceMoveToGraveyardCommandList = new ArrayList<Command>(); private ArrayList<Command> cycleCommandList = new ArrayList<Command>(); private Map<Counters, Integer> counters = new TreeMap<Counters, Integer>(); private Map<String, String> SVars = new TreeMap<String, String>(); //hacky code below, used to limit the number of times an ability //can be used per turn like Vampire Bats //should be put in SpellAbility, but it is put here for convienance //this is make public just to make things easy //this code presumes that each card only has one ability that can be //used a limited number of times per turn //CardFactory.SSP_canPlay(Card) uses these variables private int abilityUsed; //How many times has this ability been used? public void addDevoured(Card c) { devouredCards.add(c); } public void clearDevoured() { devouredCards.clear(); } public CardList getDevoured() { return devouredCards; } /** * <p>addRemembered.</p> * * @param o a {@link java.lang.Object} object. */ public void addRemembered(Object o) { rememberedObjects.add(o); } /** * <p>getRemembered.</p> * * @return a {@link java.util.ArrayList} object. */ public ArrayList<Object> getRemembered() { return rememberedObjects; } /** * <p>clearRemembered.</p> */ public void clearRemembered() { rememberedObjects.clear(); } /** * <p>addImprinted.</p> * * @param c a {@link forge.Card} object. */ public void addImprinted(Card c) { imprintedCards.add(c); } /** * <p>addImprinted.</p> * * @param list a {@link java.util.ArrayList} object. */ public void addImprinted(ArrayList<Card> list) { imprintedCards.addAll(list); } /** * <p>getImprinted.</p> * * @return a {@link java.util.ArrayList} object. */ public ArrayList<Card> getImprinted() { return imprintedCards; } /** * <p>clearImprinted.</p> */ public void clearImprinted() { imprintedCards.clear(); } /** * <p>Setter for the field <code>championedCard</code>.</p> * * @param c a {@link forge.Card} object. * @since 1.0.15 */ public void setChampionedCard(Card c) { championedCard = c; } /** * <p>Getter for the field <code>championedCard</code>.</p> * * @return a {@link forge.Card} object. * @since 1.0.15 */ public Card getChampionedCard() { return championedCard; } /** * <p>addTrigger.</p> * * @param t a {@link forge.card.trigger.Trigger} object. * @return a {@link forge.card.trigger.Trigger} object. */ public Trigger addTrigger(Trigger t) { Trigger newtrig = t.getCopy(); newtrig.setHostCard(this); triggers.add(newtrig); return newtrig; } /** * <p>removeTrigger.</p> * * @param t a {@link forge.card.trigger.Trigger} object. */ public void removeTrigger(Trigger t) { triggers.remove(t); } /** * <p>Getter for the field <code>triggers</code>.</p> * * @return a {@link java.util.ArrayList} object. */ public ArrayList<Trigger> getTriggers() { return triggers; } /** * <p>getNamedTrigger.</p> * * @param name a {@link java.lang.String} object. * @return a {@link forge.card.trigger.Trigger} object. */ public Trigger getNamedTrigger(String name) { for (Trigger t : triggers) { if (t.getName() != null && t.getName().equals(name)) { return t; } } return null; } /** * <p>Setter for the field <code>triggers</code>.</p> * * @param trigs a {@link java.util.ArrayList} object. */ public void setTriggers(ArrayList<Trigger> trigs) { for (Trigger t : trigs) { Trigger newtrig = t.getCopy(); newtrig.setHostCard(this); triggers.add(newtrig); } } /** * <p>clearTriggersNew.</p> */ public void clearTriggersNew() { triggers.clear(); } /** * <p>getTriggeringObject.</p> * * @param type a {@link java.lang.String} object. * @return a {@link java.lang.Object} object. */ public Object getTriggeringObject(String type) { return triggeringObjects.get(type); } /** * <p>Setter for the field <code>abilityUsed</code>.</p> * * @param i a int. */ public void setAbilityUsed(int i) { abilityUsed = i; } /** * <p>Getter for the field <code>abilityUsed</code>.</p> * * @return a int. */ public int getAbilityUsed() { return abilityUsed; } /** * <p>Getter for the field <code>sunburstValue</code>.</p> * * @return a int. */ public int getSunburstValue() { return sunburstValue; } /** * <p>Setter for the field <code>colorsPaid</code>.</p> * * @param s a String */ public void setColorsPaid(String s) { colorsPaid = s; } /** * <p>Getter for the field <code>colorsPaid</code>.</p> * * @return a String. */ public String getColorsPaid() { return colorsPaid; } /** * <p>Setter for the field <code>sunburstValue</code>.</p> * * @param value a int. */ public void setSunburstValue(int value) { sunburstValue = value; } //****************TOhaveDOne:Use somehow /** * <p>setX.</p> * * @param i a int. */ public void setX(int i) { X = i; } /** * <p>getX.</p> * * @return a int. */ public int getX() { return X; } //***************/ /** * <p>addXManaCostPaid.</p> * * @param n a int. */ public void addXManaCostPaid(int n) { xManaCostPaid += n; } /** * <p>Setter for the field <code>xManaCostPaid</code>.</p> * * @param n a int. */ public void setXManaCostPaid(int n) { xManaCostPaid = n; } /** * <p>Getter for the field <code>xManaCostPaid</code>.</p> * * @return a int. */ public int getXManaCostPaid() { return xManaCostPaid; } /** * <p>Setter for the field <code>xLifePaid</code>.</p> * * @param n a int. */ public void setXLifePaid(int n) { xLifePaid = n; } /** * <p>Getter for the field <code>xLifePaid</code>.</p> * * @return a int. */ public int getXLifePaid() { return xLifePaid; } //used to see if an attacking creature with a triggering attack ability triggered this phase: /** * <p>Setter for the field <code>creatureAttackedThisCombat</code>.</p> * * @param b a boolean. */ public void setCreatureAttackedThisCombat(boolean b) { creatureAttackedThisCombat = b; if (true == b) { setCreatureAttackedThisTurn(true); } } /** * <p>Getter for the field <code>creatureAttackedThisCombat</code>.</p> * * @return a boolean. */ public boolean getCreatureAttackedThisCombat() { return creatureAttackedThisCombat; } /** * <p>Setter for the field <code>creatureAttackedThisTurn</code>.</p> * * @param b a boolean. */ public void setCreatureAttackedThisTurn(boolean b) { creatureAttackedThisTurn = b; } /** * <p>Getter for the field <code>creatureAttackedThisTurn</code>.</p> * * @return a boolean. */ public boolean getCreatureAttackedThisTurn() { return creatureAttackedThisTurn; } /** * <p>Setter for the field <code>creatureBlockedThisCombat</code>.</p> * * @param b a boolean. */ public void setCreatureBlockedThisCombat(boolean b) { creatureBlockedThisCombat = b; } /** * <p>Getter for the field <code>creatureBlockedThisCombat</code>.</p> * * @return a boolean. */ public boolean getCreatureBlockedThisCombat() { return creatureBlockedThisCombat; } /** * <p>Setter for the field <code>creatureGotBlockedThisCombat</code>.</p> * * @param b a boolean. */ public void setCreatureGotBlockedThisCombat(boolean b) { creatureGotBlockedThisCombat = b; } /** * <p>Getter for the field <code>creatureGotBlockedThisCombat</code>.</p> * * @return a boolean. */ public boolean getCreatureGotBlockedThisCombat() { return creatureGotBlockedThisCombat; } /* public void setDealtCombatDmgToOppThisTurn(boolean b) { dealtCombatDmgToOppThisTurn = b; } public boolean getDealtCombatDmgToOppThisTurn() { return dealtCombatDmgToOppThisTurn; }*/ /** * <p>canAnyPlayerActivate.</p> * * @return a boolean. */ public boolean canAnyPlayerActivate() { for (SpellAbility s : spellAbility) { if (s.getRestrictions().getAnyPlayer()) return true; } return false; } /** * <p>Setter for the field <code>dealtDmgToHumanThisTurn</code>.</p> * * @param b a boolean. */ public void setDealtDmgToHumanThisTurn(boolean b) { dealtDmgToHumanThisTurn = b; } /** * <p>Getter for the field <code>dealtDmgToHumanThisTurn</code>.</p> * * @return a boolean. */ public boolean getDealtDmgToHumanThisTurn() { return dealtDmgToHumanThisTurn; } /** * <p>Setter for the field <code>dealtDmgToComputerThisTurn</code>.</p> * * @param b a boolean. */ public void setDealtDmgToComputerThisTurn(boolean b) { dealtDmgToComputerThisTurn = b; } /** * <p>Getter for the field <code>dealtDmgToComputerThisTurn</code>.</p> * * @return a boolean. */ public boolean getDealtDmgToComputerThisTurn() { return dealtDmgToComputerThisTurn; } /** * <p>Setter for the field <code>sirenAttackOrDestroy</code>.</p> * * @param b a boolean. */ public void setSirenAttackOrDestroy(boolean b) { sirenAttackOrDestroy = b; } /** * <p>Getter for the field <code>sirenAttackOrDestroy</code>.</p> * * @return a boolean. */ public boolean getSirenAttackOrDestroy() { return sirenAttackOrDestroy; } /** * <p>Getter for the field <code>clones</code>.</p> * * @return a {@link java.util.ArrayList} object. */ public ArrayList<Card> getClones() { return clones; } /** * <p>Setter for the field <code>clones</code>.</p> * * @param c a {@link java.util.ArrayList} object. */ public void setClones(ArrayList<Card> c) { clones.clear(); clones.addAll(c); } /** * <p>addClone.</p> * * @param c a {@link forge.Card} object. */ public void addClone(Card c) { clones.add(c); } /** * <p>addClones.</p> * * @param c a {@link java.util.ArrayList} object. */ public void addClones(ArrayList<Card> c) { clones.addAll(c); } /** * <p>clearClones.</p> */ public void clearClones() { clones.clear(); } /** * <p>Getter for the field <code>cloneOrigin</code>.</p> * * @return a {@link forge.Card} object. */ public Card getCloneOrigin() { return cloneOrigin; } /** * <p>Setter for the field <code>cloneOrigin</code>.</p> * * @param name a {@link forge.Card} object. */ public void setCloneOrigin(Card name) { cloneOrigin = name; } /** * <p>Getter for the field <code>cloneLeavesPlayCommand</code>.</p> * * @return a {@link forge.Command} object. */ public Command getCloneLeavesPlayCommand() { return cloneLeavesPlayCommand; } /** * <p>Setter for the field <code>cloneLeavesPlayCommand</code>.</p> * * @param com a {@link forge.Command} object. */ public void setCloneLeavesPlayCommand(Command com) { cloneLeavesPlayCommand = com; } /** * <p>Getter for the field <code>currentlyCloningCard</code>.</p> * * @return a {@link forge.Card} object. */ public Card getCurrentlyCloningCard() { return currentlyCloningCard; } /** * <p>Setter for the field <code>currentlyCloningCard</code>.</p> * * @param c a {@link forge.Card} object. */ public void setCurrentlyCloningCard(Card c) { currentlyCloningCard = c; } /** * <p>Getter for the field <code>sacrificeAtEOT</code>.</p> * * @return a boolean. */ public boolean getSacrificeAtEOT() { return sacrificeAtEOT || hasKeyword("At the beginning of the end step, sacrifice CARDNAME."); } /** * <p>Setter for the field <code>sacrificeAtEOT</code>.</p> * * @param sacrificeAtEOT a boolean. */ public void setSacrificeAtEOT(boolean sacrificeAtEOT) { this.sacrificeAtEOT = sacrificeAtEOT; } /** * <p>Getter for the field <code>bounceAtUntap</code>.</p> * * @return a boolean. */ public boolean getBounceAtUntap() { return bounceAtUntap; } /** * <p>Setter for the field <code>bounceAtUntap</code>.</p> * * @param bounce a boolean. */ public void setBounceAtUntap(boolean bounce) { this.bounceAtUntap = bounce; } /** * <p>Getter for the field <code>finishedEnteringBF</code>.</p> * * @return a boolean. */ public boolean getFinishedEnteringBF() { return finishedEnteringBF; } /** * <p>Setter for the field <code>finishedEnteringBF</code>.</p> * * @param b a boolean. */ public void setFinishedEnteringBF(boolean b) { this.finishedEnteringBF = b; } /** * <p>hasFirstStrike.</p> * * @return a boolean. */ public boolean hasFirstStrike() { return firstStrike || hasKeyword("First Strike"); } /** * <p>Setter for the field <code>firstStrike</code>.</p> * * @param firstStrike a boolean. */ public void setFirstStrike(boolean firstStrike) { this.firstStrike = firstStrike; } /** * <p>Setter for the field <code>doubleStrike</code>.</p> * * @param doubleStrike a boolean. */ public void setDoubleStrike(boolean doubleStrike) { this.doubleStrike = doubleStrike; } /** * <p>hasDoubleStrike.</p> * * @return a boolean. */ public boolean hasDoubleStrike() { return doubleStrike || hasKeyword("Double Strike"); } /** * <p>hasSecondStrike.</p> * * @return a boolean. */ public boolean hasSecondStrike() { return !hasFirstStrike() || (hasFirstStrike() && hasDoubleStrike()); } ; //for costs (like Planeswalker abilities) Doubling Season gets ignored. /** * <p>addCounterFromNonEffect.</p> * * @param counterName a {@link forge.Counters} object. * @param n a int. */ public void addCounterFromNonEffect(Counters counterName, int n) { if (this.hasKeyword("CARDNAME can't have counters placed on it.")) return; if (counters.containsKey(counterName)) { Integer aux = counters.get(counterName) + n; counters.put(counterName, aux); } else { counters.put(counterName, Integer.valueOf(n)); } if (counterName.equals(Counters.P1P1) || counterName.equals(Counters.M1M1)) { // +1/+1 counters should erase -1/-1 counters int plusOneCounters = 0; int minusOneCounters = 0; Counters p1Counter = Counters.P1P1; Counters m1Counter = Counters.M1M1; if (counters.containsKey(p1Counter)) plusOneCounters = counters.get(p1Counter); if (counters.containsKey(m1Counter)) minusOneCounters = counters.get(m1Counter); if (plusOneCounters == minusOneCounters) { counters.remove(m1Counter); counters.remove(p1Counter); } if (plusOneCounters > minusOneCounters) { counters.remove(m1Counter); counters.put(p1Counter, (Integer) (plusOneCounters - minusOneCounters)); } else { counters.put(m1Counter, (Integer) (minusOneCounters - plusOneCounters)); counters.remove(p1Counter); } } ///////////////// // // Not sure if we want to fire triggers on addCounterFromNonEffect // I don't think so since reverting cost payments uses this. /* //Run triggers HashMap<String,Object> runParams = new HashMap<String,Object>(); runParams.put("Card", this); runParams.put("CounterType", counterName); AllZone.getTriggerHandler().runTrigger("CounterAdded", runParams); */ this.updateObservers(); } /** * <p>addCounter.</p> * * @param counterName a {@link forge.Counters} object. * @param n a int. */ public void addCounter(Counters counterName, int n) { if (this.hasKeyword("CARDNAME can't have counters placed on it.")) return; int multiplier = AllZoneUtil.getDoublingSeasonMagnitude(this.getController()); if (counters.containsKey(counterName)) { Integer aux = counters.get(counterName) + (multiplier * n); counters.put(counterName, aux); } else { counters.put(counterName, Integer.valueOf(multiplier * n)); } //Run triggers Map<String, Object> runParams = new TreeMap<String, Object>(); runParams.put("Card", this); runParams.put("CounterType", counterName); for (int i = 0; i < (multiplier * n); i++) { AllZone.getTriggerHandler().runTrigger("CounterAdded", runParams); } if (counterName.equals(Counters.P1P1) || counterName.equals(Counters.M1M1)) { // +1/+1 counters should erase -1/-1 counters int plusOneCounters = 0; int minusOneCounters = 0; Counters p1Counter = Counters.P1P1; Counters m1Counter = Counters.M1M1; if (counters.containsKey(p1Counter)) plusOneCounters = counters.get(p1Counter); if (counters.containsKey(m1Counter)) minusOneCounters = counters.get(m1Counter); if (plusOneCounters == minusOneCounters) { counters.remove(m1Counter); counters.remove(p1Counter); } if (plusOneCounters > minusOneCounters) { counters.remove(m1Counter); counters.put(p1Counter, (Integer) (plusOneCounters - minusOneCounters)); } else { counters.put(m1Counter, (Integer) (minusOneCounters - plusOneCounters)); counters.remove(p1Counter); } } AllZone.getGameAction().checkStateEffects(); this.updateObservers(); } /** * <p>subtractCounter.</p> * * @param counterName a {@link forge.Counters} object. * @param n a int. */ public void subtractCounter(Counters counterName, int n) { if (counters.containsKey(counterName)) { Integer aux = counters.get(counterName) - n; if (aux < 0) aux = 0; counters.put(counterName, aux); if (counterName.equals(Counters.TIME) && aux == 0) { boolean hasVanish = CardFactory.hasKeyword(this, "Vanishing") != -1; if (hasVanish && AllZoneUtil.isCardInPlay(this)) AllZone.getGameAction().sacrifice(this); if (hasSuspend() && AllZoneUtil.isCardExiled(this)) { final Card c = this; c.setSuspendCast(true); // set activating player for base spell ability c.getSpellAbility()[0].setActivatingPlayer(c.getOwner()); // Any trigger should cause the phase not to skip AllZone.getPhase().setSkipPhase(false); AllZone.getGameAction().playCardNoCost(c); } } AllZone.getGameAction().checkStateEffects(); this.updateObservers(); } } /** * <p>Getter for the field <code>counters</code>.</p> * * @param counterName a {@link forge.Counters} object. * @return a int. */ public int getCounters(Counters counterName) { if (counters.containsKey(counterName)) { return counters.get(counterName); } else return 0; } //get all counters from a card /** * <p>Getter for the field <code>counters</code>.</p> * * @return a Map object. * @since 1.0.15 */ public Map<Counters, Integer> getCounters() { return counters; } /** * <p>hasCounters.</p> * * @return a boolean. */ public boolean hasCounters() { return counters.size() > 0; } /** * <p>setCounter.</p> * * @param counterName a {@link forge.Counters} object. * @param n a int. * @param bSetValue a boolean. */ public void setCounter(Counters counterName, int n, boolean bSetValue) { if (this.hasKeyword("CARDNAME can't have counters placed on it.")) return; if (bSetValue) // sometimes you just need to set the value without being affected by DoublingSeason counters.put(counterName, Integer.valueOf(n)); else { int num = getCounters(counterName); if (num < n) // if counters on card is less than the setting value, addCounters addCounter(counterName, n - num); else subtractCounter(counterName, num - n); } this.updateObservers(); } //get all counters from a card /** * <p>Setter for the field <code>counters</code>.</p> * * @param allCounters a Map object. * @since 1.0.15 */ public void setCounters(Map<Counters, Integer> allCounters) { counters = allCounters; } //get all counters from a card /** * <p>clearCounters.</p> * * @since 1.0.15 */ public void clearCounters() { counters = new TreeMap<Counters, Integer>(); } /** * hasLevelUp() - checks to see if a creature has the "Level up" ability introduced in Rise of the Eldrazi * * @return true if this creature can "Level up", false otherwise */ public boolean hasLevelUp() { return levelUp; } /** * <p>Setter for the field <code>levelUp</code>.</p> * * @param b a boolean. */ public void setLevelUp(boolean b) { levelUp = b; } /** * <p>getSVar.</p> * * @param Var a {@link java.lang.String} object. * @return a {@link java.lang.String} object. */ public String getSVar(String Var) { if (SVars.containsKey(Var)) return SVars.get(Var); else return ""; } /** * <p>setSVar.</p> * * @param Var a {@link java.lang.String} object. * @param str a {@link java.lang.String} object. */ public void setSVar(String Var, String str) { if (SVars.containsKey(Var)) SVars.remove(Var); SVars.put(Var, str); } /** * <p>getSVars.</p> * * @return a Map object. */ public Map<String, String> getSVars() { return SVars; } /** * <p>setSVars.</p> * * @param newSVars a Map object. */ public void setSVars(Map<String, String> newSVars) { SVars = newSVars; } /** * <p>sumAllCounters.</p> * * @return a int. */ public int sumAllCounters() { Object[] values = counters.values().toArray(); int count = 0; int num = 0; for (int i = 0; i < values.length; i++) { num = (Integer) values[i]; count += num; } return count; } /** * <p>getNetPTCounters.</p> * * @return a int. */ public int getNetPTCounters() { return getCounters(Counters.P1P1) - getCounters(Counters.M1M1); } /** * <p>Getter for the field <code>turnInZone</code>.</p> * * @return a int. */ public int getTurnInZone() { return turnInZone; } /** * <p>Setter for the field <code>turnInZone</code>.</p> * * @param turn a int. */ public void setTurnInZone(int turn) { turnInZone = turn; } /** * <p>Setter for the field <code>echoCost</code>.</p> * * @param s a {@link java.lang.String} object. */ public void setEchoCost(String s) { echoCost = s; } /** * <p>Getter for the field <code>echoCost</code>.</p> * * @return a {@link java.lang.String} object. */ public String getEchoCost() { return echoCost; } /** * <p>Setter for the field <code>manaCost</code>.</p> * * @param s a {@link java.lang.String} object. */ public void setManaCost(String s) { manaCost = s; } /** * <p>Getter for the field <code>manaCost</code>.</p> * * @return a {@link java.lang.String} object. */ public String getManaCost() { return manaCost; } /** * <p>addColor.</p> * * @param s a {@link java.lang.String} object. */ public void addColor(String s) { if (s.equals("")) s = "0"; cardColor.add(new Card_Color(new ManaCost(s), this, false, true)); } /** * <p>addColor.</p> * * @param s a {@link java.lang.String} object. * @param c a {@link forge.Card} object. * @param addToColors a boolean. * @param bIncrease a boolean. * @return a long. */ public long addColor(String s, Card c, boolean addToColors, boolean bIncrease) { if (bIncrease) Card_Color.increaseTimestamp(); cardColor.add(new Card_Color(new ManaCost(s), c, addToColors, false)); return Card_Color.getTimestamp(); } /** * <p>removeColor.</p> * * @param s a {@link java.lang.String} object. * @param c a {@link forge.Card} object. * @param addTo a boolean. * @param timestamp a long. */ public void removeColor(String s, Card c, boolean addTo, long timestamp) { Card_Color removeCol = null; for (Card_Color cc : cardColor) if (cc.equals(s, c, addTo, timestamp)) removeCol = cc; if (removeCol != null) cardColor.remove(removeCol); } /** * <p>determineColor.</p> * * @return a {@link forge.Card_Color} object. */ public Card_Color determineColor() { if (this.isImmutable()) { return new Card_Color(this); } Card_Color colors = null; ArrayList<Card_Color> globalChanges = AllZone.getGameInfo().getColorChanges(); colors = determineColor(globalChanges); colors.fixColorless(); return colors; } /** * <p>setColor.</p> * * @param colors a {@link java.util.ArrayList} object. */ public void setColor(ArrayList<Card_Color> colors) { cardColor = colors; } /** * <p>getColor.</p> * * @return a {@link java.util.ArrayList} object. */ public ArrayList<Card_Color> getColor() { return cardColor; } Card_Color determineColor(ArrayList<Card_Color> globalChanges) { Card_Color colors = new Card_Color(this); int i = cardColor.size() - 1; int j = globalChanges.size() - 1; // if both have changes, see which one is most recent while (i >= 0 && j >= 0) { Card_Color cc = null; if (cardColor.get(i).getStamp() > globalChanges.get(j).getStamp()) { // Card has a more recent color stamp cc = cardColor.get(i); i--; } else { // Global effect has a more recent color stamp cc = globalChanges.get(j); j--; } for (String s : cc.toStringArray()) colors.addToCardColor(s); if (!cc.getAdditional()) return colors; } while (i >= 0) { Card_Color cc = cardColor.get(i); i--; for (String s : cc.toStringArray()) colors.addToCardColor(s); if (!cc.getAdditional()) return colors; } while (j >= 0) { Card_Color cc = globalChanges.get(j); j--; for (String s : cc.toStringArray()) colors.addToCardColor(s); if (!cc.getAdditional()) return colors; } return colors; } /** * <p>getCMC.</p> * * @return a int. */ public int getCMC() { return CardUtil.getConvertedManaCost(manaCost); } //used for cards like Belbe's Portal, Conspiracy, Cover of Darkness, etc. /** * <p>Getter for the field <code>chosenType</code>.</p> * * @return a {@link java.lang.String} object. */ public String getChosenType() { return chosenType; } /** * <p>Setter for the field <code>chosenType</code>.</p> * * @param s a {@link java.lang.String} object. */ public void setChosenType(String s) { chosenType = s; } /** * <p>Getter for the field <code>chosenColor</code>.</p> * * @return a {@link java.lang.String} object. */ public String getChosenColor() { return chosenColor; } /** * <p>Setter for the field <code>chosenColor</code>.</p> * * @param s a {@link java.lang.String} object. */ public void setChosenColor(String s) { chosenColor = s; } //used for cards like Meddling Mage... /** * <p>Getter for the field <code>namedCard</code>.</p> * * @return a {@link java.lang.String} object. */ public String getNamedCard() { return namedCard; } /** * <p>Setter for the field <code>namedCard</code>.</p> * * @param s a {@link java.lang.String} object. */ public void setNamedCard(String s) { namedCard = s; } /** * <p>Setter for the field <code>drawnThisTurn</code>.</p> * * @param b a boolean. */ public void setDrawnThisTurn(boolean b) { drawnThisTurn = b; } /** * <p>Getter for the field <code>drawnThisTurn</code>.</p> * * @return a boolean. */ public boolean getDrawnThisTurn() { return drawnThisTurn; } /** * <p>Getter for the field <code>reflectableMana</code>.</p> * * @return a {@link java.lang.String} object. */ public String getReflectableMana() { return reflectableMana; } /** * <p>Setter for the field <code>reflectableMana</code>.</p> * * @param s a {@link java.lang.String} object. */ public void setReflectableMana(String s) { reflectableMana = s; } /** * get a list of Cards this card has gained control of * <p/> * used primarily with AbilityFactory_GainControl * * @return a list of cards this card has gained control of */ public ArrayList<Card> getGainControlTargets() { return gainControlTargets; } /** * add a Card to the list of Cards this card has gained control of * <p/> * used primarily with AbilityFactory_GainControl * * @param c a {@link forge.Card} object. */ public void addGainControlTarget(Card c) { gainControlTargets.add(c); } /** * clear the list of Cards this card has gained control of * <p/> * used primarily with AbilityFactory_GainControl */ public void clearGainControlTargets() { gainControlTargets.clear(); } /** * get the commands to be executed to lose control of Cards this * card has gained control of * <p/> * used primarily with AbilityFactory_GainControl (Old Man of the Sea specifically) * * @return a {@link java.util.ArrayList} object. */ public ArrayList<Command> getGainControlReleaseCommands() { return gainControlReleaseCommands; } /** * set a command to be executed to lose control of Cards this * card has gained control of * <p/> * used primarily with AbilityFactory_GainControl (Old Man of the Sea specifically) * * @param c the Command to be executed */ public void addGainControlReleaseCommand(Command c) { gainControlReleaseCommands.add(c); } /** * <p>clearGainControlReleaseCommands.</p> */ public void clearGainControlReleaseCommands() { gainControlReleaseCommands.clear(); } /** * <p>getSpellText.</p> * * @return a {@link java.lang.String} object. */ public String getSpellText() { return text; } /** * <p>Setter for the field <code>text</code>.</p> * * @param t a {@link java.lang.String} object. */ public void setText(String t) { text = t; } // get the text that should be displayed /** * <p>Getter for the field <code>text</code>.</p> * * @return a {@link java.lang.String} object. */ public String getText() { StringBuilder sb = new StringBuilder(); sb.append(this.getAbilityText()); String NonAbilityText = getNonAbilityText(); if (NonAbilityText.length() > 0) { sb.append("\r\n \r\nNon ability features: \r\n"); sb.append(NonAbilityText.replaceAll("CARDNAME", getName())); } return sb.toString(); } // get the text that does not belong to a cards abilities (and is not really there ruleswise) /** * <p>getNonAbilityText.</p> * * @return a {@link java.lang.String} object. */ public String getNonAbilityText() { StringBuilder sb = new StringBuilder(); ArrayList<String> keyword = getHiddenExtrinsicKeyword(); sb.append(keywordsToText(keyword)); return sb.toString(); } // convert a keyword list to the String that should be displayed ingame /** * <p>keywordsToText.</p> * * @param keyword a {@link java.util.ArrayList} object. * @return a {@link java.lang.String} object. */ public String keywordsToText(ArrayList<String> keyword) { StringBuilder sb = new StringBuilder(); StringBuilder sbLong = new StringBuilder(); StringBuilder sbMana = new StringBuilder(); for (int i = 0; i < keyword.size(); i++) { if (!keyword.get(i).toString().contains("CostChange") && !keyword.get(i).toString().contains("Permanents don't untap during their controllers' untap steps") && !keyword.get(i).toString().contains("PreventAllDamageBy") && !keyword.get(i).toString().contains("CantBeBlockedBy")) { if (keyword.get(i).toString().contains("StaticEffect")) { String k[] = keyword.get(i).split(":"); sbLong.append(k[5]).append("\r\n"); } else if (keyword.get(i).toString().contains("stPump")) { String k[] = keyword.get(i).split(":", 5); if (!k[4].contains("no text")) sbLong.append(k[4]).append("\r\n"); /*} else if (keyword.get(i).toString().contains("stSetPT")) { String k[] = keyword.get(i).split(":", 10); if (k.length > 8) sbLong.append(k[9]).append("\r\n"); else if (k.length > 5) sbLong.append(k[6]).append("\r\n"); else sbLong.append(k[3]).append("\r\n");*/ } else if (keyword.get(i).toString().contains("stAnimate")) { String k[] = keyword.get(i).split(":", 8); if (!k[7].contains("no text")) sbLong.append(k[7]).append("\r\n"); } else if (keyword.get(i).toString().contains("Protection:")) { String k[] = keyword.get(i).split(":"); sbLong.append(k[2]).append("\r\n"); } else if (keyword.get(i).toString().contains("stPreventDamage:")) { String k[] = keyword.get(i).split(":"); if (!k[4].equals("no text")) sbLong.append(k[4]).append("\r\n"); } else if (keyword.get(i).toString().contains("Creatures can't attack unless their controller pays")) { String k[] = keyword.get(i).split(":"); if (!k[3].equals("no text")) sbLong.append(k[3]).append("\r\n"); } else if (keyword.get(i).startsWith("Enchant")) { String k = keyword.get(i); k = k.replace("Curse", ""); sbLong.append(k).append("\r\n"); } else if (keyword.get(i).startsWith("Soulshift") || keyword.get(i).startsWith("Cumulative upkeep") || keyword.get(i).startsWith("Echo") || keyword.get(i).startsWith("Fading") || keyword.get(i).startsWith("Ripple") || keyword.get(i).startsWith("Unearth") || keyword.get(i).startsWith("Vanishing") || keyword.get(i).startsWith("Madness") || keyword.get(i).startsWith("Devour")) { String k = keyword.get(i); k = k.replace(":", " "); sbLong.append(k).append("\r\n"); } else if (keyword.get(i).startsWith("Champion")) { String k = getKeyword().get(i); String kk[] = k.split(":"); String types = kk[1]; if (kk.length > 2) types = kk[2]; if (kk[1].equals("Creature")) kk[1] = kk[1].toLowerCase(); sbLong.append("Champion a"); if (kk[1].toLowerCase().startsWith("a") || kk[1].toLowerCase().startsWith("e") || kk[1].toLowerCase().startsWith("i") || kk[1].toLowerCase().startsWith("o") || kk[1].toLowerCase().startsWith("u")) { sbLong.append("n"); } sbLong.append(" ").append(types); sbLong.append(" (When this enters the battlefield, sacrifice it unless you exile another ").append(types); sbLong.append(" you control. When this leaves the battlefield, that card returns to the battlefield.)\r\n"); } else if (keyword.get(i).endsWith(".")) { sbLong.append(keyword.get(i).toString()).append("\r\n"); } else if (keyword.get(i).contains("At the beginning of your upkeep, ") && keyword.get(i).contains(" unless you pay")) { sbLong.append(keyword.get(i).toString()).append("\r\n"); } else if (keyword.get(i).toString().contains("tap: add ")) { sbMana.append(keyword.get(i).toString()).append("\r\n"); } else if (keyword.get(i).contains("Bloodthirst")) { String k = keyword.get(i); String kk[] = k.split(" "); sbLong.append(keyword.get(i)).append(" (If an opponent was dealt damage this turn, this creature enters the battlefield with "); sbLong.append(kk[1]).append(" +1/+1 counter"); if (Integer.parseInt(kk[1]) > 1) { sbLong.append("s"); } sbLong.append(" on it.)").append("\r\n"); } else if (keyword.get(i).startsWith("Modular")) { String numCounters = keyword.get(i).split(" ")[1]; sbLong.append(keyword.get(i)); sbLong.append(" (This enters the battlefield with "); sbLong.append(numCounters); sbLong.append(" +1/+1 counters on it. When it's put into a graveyard, you may put its +1/+1 counters on target artifact creature.)"); } else { if (i != 0 && sb.length() != 0) sb.append(", "); sb.append(keyword.get(i).toString()); } } } if (sb.length() > 0) sb.append("\r\n\r\n"); if (sbLong.length() > 0) sbLong.append("\r\n"); sb.append(sbLong); sb.append(sbMana); return sb.toString(); } //get the text of the abilities of a card /** * <p>getAbilityText.</p> * * @return a {@link java.lang.String} object. */ public String getAbilityText() { if (isInstant() || isSorcery()) { String s = getSpellText(); StringBuilder sb = new StringBuilder(); // Give spellText line breaks for easier reading sb.append(s.replaceAll("\\\\r\\\\n", "\r\n")); // NOTE: if (sb.toString().contains(" (NOTE: ")) { sb.insert(sb.indexOf("(NOTE: "), "\r\n"); } if (sb.toString().contains("(NOTE: ") && sb.toString().endsWith(".)") && !sb.toString().endsWith("\r\n")) { sb.append("\r\n"); } // Add SpellAbilities SpellAbility[] sa = getSpellAbility(); for (int i = 0; i < sa.length; i++) { sb.append(sa[i].toString() + "\r\n"); } // Add Keywords ArrayList<String> kw = getKeyword(); // Triggered abilities for (Trigger trig : triggers) { if (!trig.isSecondary()) { sb.append(trig.toString() + "\r\n"); } } // static abilities for (StaticAbility stAb : staticAbilities) { String stAbD = stAb.toString(); if (!stAbD.equals("")) sb.append(stAbD + "\r\n"); } // Ripple + Dredge + Madness + CARDNAME is {color} + Recover. for (int i = 0; i < kw.size(); i++) { if ((kw.get(i).startsWith("Ripple") && !sb.toString().contains("Ripple")) || (kw.get(i).startsWith("Dredge") && !sb.toString().contains("Dredge")) || (kw.get(i).startsWith("Madness") && !sb.toString().contains("Madness")) || (kw.get(i).startsWith("CARDNAME is ") && !sb.toString().contains("CARDNAME is ")) || (kw.get(i).startsWith("Recover") && !sb.toString().contains("Recover"))) { sb.append(kw.get(i).replace(":", " ")).append("\r\n"); } } // Changeling + CARDNAME can't be countered. + Cascade + Multikicker for (int i = 0; i < kw.size(); i++) { if ((kw.get(i).contains("Changeling") && !sb.toString().contains("Changeling")) || (kw.get(i).contains("CARDNAME can't be countered.") && !sb.toString().contains("CARDNAME can't be countered.")) || (kw.get(i).contains("Cascade") && !sb.toString().contains("Cascade")) || (kw.get(i).contains("Multikicker") && !sb.toString().contains("Multikicker"))) { sb.append(kw.get(i)).append("\r\n"); } } // Storm if (hasKeyword("Storm") && !sb.toString().contains("Storm (When you ")) { if (sb.toString().endsWith("\r\n\r\n")) { sb.delete(sb.lastIndexOf("\r\n"), sb.lastIndexOf("\r\n") + 3); } sb.append("Storm (When you cast this spell, copy it for each spell cast before it this turn."); if (sb.toString().contains("Target") || sb.toString().contains("target")) { sb.append(" You may choose new targets for the copies."); } sb.append(")\r\n"); } //Replicate for (String keyw : kw) { if (keyw.contains("Replicate") && !sb.toString().contains("you paid its replicate cost.")) { if (sb.toString().endsWith("\r\n\r\n")) { sb.delete(sb.lastIndexOf("\r\n"), sb.lastIndexOf("\r\n") + 3); } sb.append(keyw); sb.append(" (When you cast this spell, copy it for each time you paid its replicate cost."); if (sb.toString().contains("Target") || sb.toString().contains("target")) { sb.append(" You may choose new targets for the copies."); } sb.append(")\r\n"); } } while (sb.toString().endsWith("\r\n")) { sb.delete(sb.lastIndexOf("\r\n"), sb.lastIndexOf("\r\n") + 3); } return sb.toString().replaceAll("CARDNAME", getName()); } StringBuilder sb = new StringBuilder(); ArrayList<String> keyword = getUnhiddenKeyword(); sb.append(keywordsToText(keyword)); // Give spellText line breaks for easier reading sb.append("\r\n"); sb.append(text.replaceAll("\\\\r\\\\n", "\r\n")); sb.append("\r\n"); /* * if(isAura()) { // Give spellText line breaks for easier reading sb.append(getSpellText().replaceAll("\\\\r\\\\n", "\r\n")).append("\r\n"); } */ // Triggered abilities for (Trigger trig : triggers) { if (!trig.isSecondary()) { sb.append(trig.toString() + "\r\n"); } } // static abilities for (StaticAbility stAb : staticAbilities) { sb.append(stAb.toString() + "\r\n"); } ArrayList<String> addedManaStrings = new ArrayList<String>(); SpellAbility[] abilities = getSpellAbility(); boolean primaryCost = true; for (SpellAbility sa : abilities) { // only add abilities not Spell portions of cards if (!isPermanent()) continue; if (sa instanceof Spell_Permanent && primaryCost && !isAura()) { // For Alt costs, make sure to display the cost! primaryCost = false; continue; } String sAbility = sa.toString(); if (sa instanceof Ability_Mana) { if (addedManaStrings.contains(sAbility)) continue; addedManaStrings.add(sAbility); } if (sa instanceof Spell_Permanent && !isAura()) { sb.insert(0, "\r\n"); sb.insert(0, sAbility); } else if (!sAbility.endsWith(getName())) { sb.append(sAbility); sb.append("\r\n"); // The test above appears to prevent the card name from showing and therefore it no longer needs to be deleted from the stringbuilder //if (sb.toString().endsWith("CARDNAME")) // sb.replace(sb.toString().lastIndexOf("CARDNAME"), sb.toString().lastIndexOf("CARDNAME") + name.length() - 1, ""); } } // NOTE: if (sb.toString().contains(" (NOTE: ")) { sb.insert(sb.indexOf("(NOTE: "), "\r\n"); } if (sb.toString().contains("(NOTE: ") && sb.toString().contains(".) ")) { sb.insert(sb.indexOf(".) ") + 3, "\r\n"); } // replace tripple line feeds with double line feeds int start; String s = "\r\n\r\n\r\n"; while (sb.toString().contains(s)) { start = sb.lastIndexOf(s); if (start < 0 || start >= sb.length()) break; sb.replace(start, start + 4, "\r\n"); } //Remembered cards if (rememberedObjects.size() > 0) { sb.append("\r\nRemembered: \r\n"); for (Object o : rememberedObjects) { if (o instanceof Card) { Card c = (Card) o; sb.append(c.getName()); sb.append("("); sb.append(c.getUniqueNumber()); sb.append(")"); } else sb.append(o.toString()); sb.append("\r\n"); } } return sb.toString().replaceAll("CARDNAME", getName()).trim(); }//getText() /** * <p>Getter for the field <code>manaAbility</code>.</p> * * @return a {@link java.util.ArrayList} object. */ public ArrayList<Ability_Mana> getManaAbility() { return new ArrayList<Ability_Mana>(manaAbility); } // Returns basic mana abilities plus "reflected mana" abilities /** * <p>getAIPlayableMana.</p> * * @return a {@link java.util.ArrayList} object. */ public ArrayList<Ability_Mana> getAIPlayableMana() { ArrayList<Ability_Mana> res = new ArrayList<Ability_Mana>(); for (Ability_Mana am : getManaAbility()) if (am.isBasic() && !res.contains(am)) { res.add(am); } else if (am.isReflectedMana() && !res.contains(am)) { res.add(am); } return res; } /** * <p>getBasicMana.</p> * * @return a {@link java.util.ArrayList} object. */ public ArrayList<Ability_Mana> getBasicMana() { ArrayList<Ability_Mana> res = new ArrayList<Ability_Mana>(); for (Ability_Mana am : getManaAbility()) if (am.isBasic() && !res.contains(am)) res.add(am); return res; } /** * <p>clearFirstSpellAbility.</p> */ public void clearFirstSpell() { for(int i = 0; i < spellAbility.size(); i++){ if (spellAbility.get(i).isSpell()){ spellAbility.remove(i); return; } } } /** * <p>clearAllButFirstSpellAbility.</p> */ public void clearAllButFirstSpellAbility() { if (!spellAbility.isEmpty()) { SpellAbility first = spellAbility.get(0); spellAbility.clear(); spellAbility.add(first); } manaAbility.clear(); } /** * <p>getAllButFirstSpellAbility.</p> * * @return a {@link java.util.ArrayList} object. */ public ArrayList<SpellAbility> getAllButFirstSpellAbility() { ArrayList<SpellAbility> sas = new ArrayList<SpellAbility>(); sas.addAll(spellAbility); if (!sas.isEmpty()) { SpellAbility first = spellAbility.get(0); sas.remove(first); } sas.addAll(manaAbility); return sas; } /** * <p>clearSpellAbility.</p> */ public void clearSpellAbility() { spellAbility.clear(); manaAbility.clear(); } /** * <p>getSpellPermanent.</p> * * @return a {@link forge.card.spellability.Spell_Permanent} object. */ public Spell_Permanent getSpellPermanent() { for (SpellAbility sa : spellAbility) { if (sa instanceof Spell_Permanent) return (Spell_Permanent) sa; } return null; } /** * <p>clearSpellKeepManaAbility.</p> */ public void clearSpellKeepManaAbility() { spellAbility.clear(); } /** * <p>clearManaAbility.</p> */ public void clearManaAbility() { manaAbility.clear(); } /** * <p>addFirstSpellAbility.</p> * * @param a a {@link forge.card.spellability.SpellAbility} object. */ public void addFirstSpellAbility(SpellAbility a) { a.setSourceCard(this); if (a instanceof Ability_Mana) manaAbility.add(0, (Ability_Mana) a); else spellAbility.add(0, a); } /** * <p>addSpellAbility.</p> * * @param a a {@link forge.card.spellability.SpellAbility} object. */ public void addSpellAbility(SpellAbility a) { a.setSourceCard(this); if (a instanceof Ability_Mana) manaAbility.add((Ability_Mana) a); else spellAbility.add(a); } /** * <p>removeSpellAbility.</p> * * @param a a {@link forge.card.spellability.SpellAbility} object. */ public void removeSpellAbility(SpellAbility a) { if (a instanceof Ability_Mana) //if (a.isExtrinsic()) //never remove intrinsic mana abilities, is this the way to go?? manaAbility.remove(a); else spellAbility.remove(a); } /** * <p>removeAllExtrinsicManaAbilities.</p> */ public void removeAllExtrinsicManaAbilities() { //temp ArrayList, otherwise ConcurrentModificationExceptions occur: ArrayList<SpellAbility> saList = new ArrayList<SpellAbility>(); for (SpellAbility var : manaAbility) { if (var.isExtrinsic()) saList.add(var); } for (SpellAbility sa : saList) { removeSpellAbility(sa); } } /** * <p>getIntrinsicManaAbilitiesDescriptions.</p> * * @return a {@link java.util.ArrayList} object. */ public ArrayList<String> getIntrinsicManaAbilitiesDescriptions() { ArrayList<String> list = new ArrayList<String>(); for (SpellAbility var : manaAbility) { if (var.isIntrinsic()) list.add(var.toString()); } return list; } /** * <p>Getter for the field <code>spellAbility</code>.</p> * * @return an array of {@link forge.card.spellability.SpellAbility} objects. */ public SpellAbility[] getSpellAbility() { ArrayList<SpellAbility> res = new ArrayList<SpellAbility>(spellAbility); res.addAll(getManaAbility()); SpellAbility[] s = new SpellAbility[res.size()]; res.toArray(s); return s; } /** * <p>getSpellAbilities.</p> * * @return a {@link java.util.ArrayList} object. */ public ArrayList<SpellAbility> getSpellAbilities() { ArrayList<SpellAbility> res = new ArrayList<SpellAbility>(spellAbility); res.addAll(getManaAbility()); return res; } /** * <p>getSpells.</p> * * @return a {@link java.util.ArrayList} object. */ public ArrayList<SpellAbility> getSpells() { ArrayList<SpellAbility> s = new ArrayList<SpellAbility>(spellAbility); ArrayList<SpellAbility> res = new ArrayList<SpellAbility>(); for (SpellAbility sa : s) { if (sa.isSpell()) res.add(sa); } return res; } /** * <p>getBasicSpells.</p> * * @return a {@link java.util.ArrayList} object. */ public ArrayList<SpellAbility> getBasicSpells() { ArrayList<SpellAbility> s = new ArrayList<SpellAbility>(spellAbility); ArrayList<SpellAbility> res = new ArrayList<SpellAbility>(); for (SpellAbility sa : s) { if (sa.isSpell() && !sa.isFlashBackAbility() && !sa.isBuyBackAbility()) res.add(sa); } return res; } /** * <p>getAdditionalCostSpells.</p> * * @return a {@link java.util.ArrayList} object. */ public ArrayList<SpellAbility> getAdditionalCostSpells() { ArrayList<SpellAbility> s = new ArrayList<SpellAbility>(spellAbility); ArrayList<SpellAbility> res = new ArrayList<SpellAbility>(); for (SpellAbility sa : s) { if (sa.isSpell() && !sa.getAdditionalManaCost().equals("")) res.add(sa); } return res; } //PreventNextDamage /** * <p>Setter for the field <code>preventNextDamage</code>.</p> * * @param n a int. */ public void setpreventNextDamage(int n) { preventNextDamage = n; } /** * <p>Getter for the field <code>preventNextDamage</code>.</p> * * @return a int. */ public int getPreventNextDamage() { return preventNextDamage; } /** * <p>addPreventNextDamage.</p> * * @param n a int. */ public void addPreventNextDamage(int n) { preventNextDamage += n; } /** * <p>subtractPreventNextDamage.</p> * * @param n a int. */ public void subtractPreventNextDamage(int n) { preventNextDamage -= n; } /** * <p>resetPreventNextDamage.</p> */ public void resetPreventNextDamage() { preventNextDamage = 0; } //shield = regeneration /** * <p>setShield.</p> * * @param n a int. */ public void setShield(int n) { nShield = n; } /** * <p>getShield.</p> * * @return a int. */ public int getShield() { return nShield; } /** * <p>addShield.</p> */ public void addShield() { nShield++; } /** * <p>subtractShield.</p> */ public void subtractShield() { nShield--; } /** * <p>resetShield.</p> */ public void resetShield() { nShield = 0; } /** * <p>canBeShielded.</p> * * @return a boolean. */ public boolean canBeShielded() { return !hasKeyword("CARDNAME can't be regenerated."); } //is this "Card" supposed to be a token? /** * <p>Setter for the field <code>token</code>.</p> * * @param b a boolean. */ public void setToken(boolean b) { token = b; } /** * <p>isToken.</p> * * @return a boolean. */ public boolean isToken() { return token; } /** * <p>Setter for the field <code>copiedToken</code>.</p> * * @param b a boolean. */ public void setCopiedToken(boolean b) { copiedToken = b; } /** * <p>isCopiedToken.</p> * * @return a boolean. */ public boolean isCopiedToken() { return copiedToken; } /** * <p>Setter for the field <code>copiedSpell</code>.</p> * * @param b a boolean. */ public void setCopiedSpell(boolean b) { copiedSpell = b; } /** * <p>isCopiedSpell.</p> * * @return a boolean. */ public boolean isCopiedSpell() { return copiedSpell; } /** * <p>addSpellChoice.</p> * * @param string a {@link java.lang.String} object. */ public void addSpellChoice(String string) { ChoicesMade.add(string); } /** * <p>getChoices.</p> * * @return a {@link java.util.ArrayList} object. */ public ArrayList<String> getChoices() { return ChoicesMade; } /** * <p>getChoice.</p> * * @param i a int. * @return a {@link java.lang.String} object. */ public String getChoice(int i) { return ChoicesMade.get(i); } /** * <p>setSpellChoiceTarget.</p> * * @param string a {@link java.lang.String} object. */ public void setSpellChoiceTarget(String string) { Targets_for_Choices.add(string); } /** * <p>getChoiceTargets.</p> * * @return a {@link java.util.ArrayList} object. */ public ArrayList<String> getChoiceTargets() { return Targets_for_Choices; } /** * <p>getChoiceTarget.</p> * * @param i a int. * @return a {@link java.lang.String} object. */ public String getChoiceTarget(int i) { return Targets_for_Choices.get(i); } /** * <p>setSpellWithChoices.</p> * * @param b a boolean. */ public void setSpellWithChoices(boolean b) { SpellwithChoices = b; } /** * <p>hasChoices.</p> * * @return a boolean. */ public boolean hasChoices() { return SpellwithChoices; } /** * <p>setCopiesSpells.</p> * * @param b a boolean. */ public void setCopiesSpells(boolean b) { SpellCopyingCard = b; } /** * <p>copiesSpells.</p> * * @return a boolean. */ public boolean copiesSpells() { return SpellCopyingCard; } /** * <p>Setter for the field <code>exaltedBonus</code>.</p> * * @param b a boolean. */ public void setExaltedBonus(boolean b) { exaltedBonus = b; } /** * <p>hasExaltedBonus.</p> * * @return a boolean. */ public boolean hasExaltedBonus() { return exaltedBonus; } /** * <p>setIsFaceDown.</p> * * @param b a boolean. */ public void setIsFaceDown(boolean b) { faceDown = b; } /** * <p>isFaceDown.</p> * * @return a boolean. */ public boolean isFaceDown() { return faceDown; } /** * <p>addTrigger.</p> * * @param c a {@link forge.Command} object. * @param type a {@link forge.ZCTrigger} object. */ public void addTrigger(Command c, ZCTrigger type) { zcTriggers.add(new Ability_Triggered(this, c, type)); } /** * <p>removeTrigger.</p> * * @param c a {@link forge.Command} object. * @param type a {@link forge.ZCTrigger} object. */ public void removeTrigger(Command c, ZCTrigger type) { zcTriggers.remove(new Ability_Triggered(this, c, type)); } /** * <p>executeTrigger.</p> * * @param type a {@link forge.ZCTrigger} object. */ public void executeTrigger(ZCTrigger type) { for (Ability_Triggered t : zcTriggers) if (t.trigger.equals(type) && t.isBasic()) t.execute();//AllZone.getStack().addSimultaneousStackEntry(t); } /** * <p>clearTriggers.</p> */ public void clearTriggers() { zcTriggers.clear(); } /** * <p>addComesIntoPlayCommand.</p> * * @param c a {@link forge.Command} object. */ public void addComesIntoPlayCommand(Command c) { addTrigger(c, ZCTrigger.ENTERFIELD); } /** * <p>removeComesIntoPlayCommand.</p> * * @param c a {@link forge.Command} object. */ public void removeComesIntoPlayCommand(Command c) { removeTrigger(c, ZCTrigger.ENTERFIELD); } /** * <p>comesIntoPlay.</p> */ public void comesIntoPlay() { executeTrigger(ZCTrigger.ENTERFIELD); } /** * <p>addTurnFaceUpCommand.</p> * * @param c a {@link forge.Command} object. */ public void addTurnFaceUpCommand(Command c) { turnFaceUpCommandList.add(c); } /** * <p>removeTurnFaceUpCommand.</p> * * @param c a {@link forge.Command} object. */ public void removeTurnFaceUpCommand(Command c) { turnFaceUpCommandList.remove(c); } /** * <p>turnFaceUp.</p> */ public void turnFaceUp() { for (Command var : turnFaceUpCommandList) var.execute(); //Run triggers Map<String, Object> runParams = new TreeMap<String, Object>(); runParams.put("Card", this); AllZone.getTriggerHandler().runTrigger("TurnFaceUp", runParams); } /** * <p>addDestroyCommand.</p> * * @param c a {@link forge.Command} object. */ public void addDestroyCommand(Command c) { addTrigger(c, ZCTrigger.DESTROY); } /** * <p>removeDestroyCommand.</p> * * @param c a {@link forge.Command} object. */ public void removeDestroyCommand(Command c) { removeTrigger(c, ZCTrigger.DESTROY); } /** * <p>destroy.</p> */ public void destroy() { executeTrigger(ZCTrigger.DESTROY); } /** * <p>addLeavesPlayCommand.</p> * * @param c a {@link forge.Command} object. */ public void addLeavesPlayCommand(Command c) { addTrigger(c, ZCTrigger.LEAVEFIELD); } /** * <p>removeLeavesPlayCommand.</p> * * @param c a {@link forge.Command} object. */ public void removeLeavesPlayCommand(Command c) { removeTrigger(c, ZCTrigger.LEAVEFIELD); } /** * <p>leavesPlay.</p> */ public void leavesPlay() { executeTrigger(ZCTrigger.LEAVEFIELD); } /** * <p>addEquipCommand.</p> * * @param c a {@link forge.Command} object. */ public void addEquipCommand(Command c) { equipCommandList.add(c); } /** * <p>removeEquipCommand.</p> * * @param c a {@link forge.Command} object. */ public void removeEquipCommand(Command c) { equipCommandList.remove(c); } /** * <p>equip.</p> */ public void equip() { for (Command var : equipCommandList) var.execute(); } /** * <p>addUnEquipCommand.</p> * * @param c a {@link forge.Command} object. */ public void addUnEquipCommand(Command c) { unEquipCommandList.add(c); } /** * <p>removeUnEquipCommand.</p> * * @param c a {@link forge.Command} object. */ public void removeUnEquipCommand(Command c) { unEquipCommandList.remove(c); } /** * <p>unEquip.</p> */ public void unEquip() { for (Command var : unEquipCommandList) var.execute(); } /** * <p>addEnchantCommand.</p> * * @param c a {@link forge.Command} object. */ public void addEnchantCommand(Command c) { enchantCommandList.add(c); } /** * <p>clearEnchantCommand.</p> */ public void clearEnchantCommand() { enchantCommandList.clear(); } /** * <p>enchant.</p> */ public void enchant() { for (Command var : enchantCommandList) var.execute(); } /** * <p>addUnEnchantCommand.</p> * * @param c a {@link forge.Command} object. */ public void addUnEnchantCommand(Command c) { unEnchantCommandList.add(c); } /** * <p>clearUnEnchantCommand.</p> */ public void clearUnEnchantCommand() { unEnchantCommandList.clear(); } /** * <p>unEnchant.</p> */ public void unEnchant() { for (Command var : unEnchantCommandList) var.execute(); } /** * <p>addUntapCommand.</p> * * @param c a {@link forge.Command} object. */ public void addUntapCommand(Command c) { untapCommandList.add(c); } /** * <p>addChangeControllerCommand.</p> * * @param c a {@link forge.Command} object. */ public void addChangeControllerCommand(Command c) { changeControllerCommandList.add(c); } /** * <p>getReplaceMoveToGraveyard.</p> * * @return a {@link java.util.ArrayList} object. */ public ArrayList<Command> getReplaceMoveToGraveyard() { return replaceMoveToGraveyardCommandList; } /** * <p>addReplaceMoveToGraveyardCommand.</p> * * @param c a {@link forge.Command} object. */ public void addReplaceMoveToGraveyardCommand(Command c) { replaceMoveToGraveyardCommandList.add(c); } /** * <p>clearReplaceMoveToGraveyardCommandList.</p> */ public void clearReplaceMoveToGraveyardCommandList() { replaceMoveToGraveyardCommandList.clear(); } /** * <p>replaceMoveToGraveyard.</p> */ public void replaceMoveToGraveyard() { for (Command var : replaceMoveToGraveyardCommandList) var.execute(); } /** * <p>addCycleCommand.</p> * * @param c a {@link forge.Command} object. */ public void addCycleCommand(Command c) { cycleCommandList.add(c); } /** * <p>cycle.</p> */ public void cycle() { for (Command var : cycleCommandList) var.execute(); } /** * <p>Setter for the field <code>sickness</code>.</p> * * @param b a boolean. */ public void setSickness(boolean b) { sickness = b; } /** * <p>hasSickness.</p> * * @return a boolean. */ public boolean hasSickness() { if (hasKeyword("Haste")) return false; return sickness; } /** * <p>isSick.</p> * * @return a boolean. */ public boolean isSick() { if (hasKeyword("Haste")) return false; return sickness && isCreature(); } /** * <p>Setter for the field <code>rarity</code>.</p> * * @param s a {@link java.lang.String} object. */ public void setRarity(String s) { rarity = s; } /** * <p>Getter for the field <code>rarity</code>.</p> * * @return a {@link java.lang.String} object. */ public String getRarity() { return rarity; } /** * <p>Setter for the field <code>imageName</code>.</p> * * @param s a {@link java.lang.String} object. */ public void setImageName(String s) { imageName = s; } /** * <p>Getter for the field <code>imageName</code>.</p> * * @return a {@link java.lang.String} object. */ public String getImageName() { if (!imageName.equals("")) return imageName; return name; } /** * <p>Getter for the field <code>name</code>.</p> * * @return a {@link java.lang.String} object. */ public String getName() { return name; } /** * <p>Getter for the field <code>owner</code>.</p> * * @return a {@link forge.Player} object. */ public Player getOwner() { return owner; } /** * <p>Getter for the field <code>controller</code>.</p> * * @return a {@link forge.Player} object. */ public Player getController() { return controller; } /** * <p>Setter for the field <code>name</code>.</p> * * @param s a {@link java.lang.String} object. */ public void setName(String s) { name = s; this.updateObservers(); } /** * <p>Setter for the field <code>owner</code>.</p> * * @param player a {@link forge.Player} object. */ public void setOwner(Player player) { owner = player; this.updateObservers(); } /** * <p>Setter for the field <code>controller</code>.</p> * * @param player a {@link forge.Player} object. */ public void setController(Player player) { boolean sameController = controller == null ? false : controller.isPlayer(player); controller = player; if (null != controller && !sameController) { for (Command var : changeControllerCommandList) var.execute(); } this.updateObservers(); } /** * <p>Getter for the field <code>equippedBy</code>.</p> * * @return a {@link java.util.ArrayList} object. */ public ArrayList<Card> getEquippedBy() { return equippedBy; } /** * <p>Setter for the field <code>equippedBy</code>.</p> * * @param list a {@link java.util.ArrayList} object. */ public void setEquippedBy(ArrayList<Card> list) { equippedBy = list; } /** * <p>Getter for the field <code>equipping</code>.</p> * * @return a {@link java.util.ArrayList} object. */ public ArrayList<Card> getEquipping() { return equipping; } /** * <p>getEquippingCard.</p> * * @return a {@link forge.Card} object. */ public Card getEquippingCard() { if (equipping.size() == 0) return null; return equipping.get(0); } /** * <p>Setter for the field <code>equipping</code>.</p> * * @param list a {@link java.util.ArrayList} object. */ public void setEquipping(ArrayList<Card> list) { equipping = list; } /** * <p>isEquipped.</p> * * @return a boolean. */ public boolean isEquipped() { return equippedBy.size() != 0; } /** * <p>isEquipping.</p> * * @return a boolean. */ public boolean isEquipping() { return equipping.size() != 0; } /** * <p>addEquippedBy.</p> * * @param c a {@link forge.Card} object. */ public void addEquippedBy(Card c) { equippedBy.add(c); this.updateObservers(); } /** * <p>removeEquippedBy.</p> * * @param c a {@link forge.Card} object. */ public void removeEquippedBy(Card c) { equippedBy.remove(c); this.updateObservers(); } /** * <p>addEquipping.</p> * * @param c a {@link forge.Card} object. */ public void addEquipping(Card c) { equipping.add(c); this.updateObservers(); } /** * <p>removeEquipping.</p> * * @param c a {@link forge.Card} object. */ public void removeEquipping(Card c) { equipping.remove(c); this.updateObservers(); } /** * <p>equipCard.</p> * * @param c a {@link forge.Card} object. */ public void equipCard(Card c) //equipment.equipCard(cardToBeEquipped); { equipping.add(c); c.addEquippedBy(this); this.equip(); } /** * <p>unEquipCard.</p> * * @param c a {@link forge.Card} object. */ public void unEquipCard(Card c) //equipment.unEquipCard(equippedCard); { this.unEquip(); equipping.remove(c); c.removeEquippedBy(this); //Run triggers Map<String, Object> runParams = new TreeMap<String, Object>(); runParams.put("Equipment", this); runParams.put("Card", c); AllZone.getTriggerHandler().runTrigger("Unequip", runParams); } /** * <p>unEquipAllCards.</p> */ public void unEquipAllCards() { while (equippedBy.size() > 0) { // while there exists equipment, unequip the first one equippedBy.get(0).unEquipCard(this); } } /** * <p>Getter for the field <code>enchantedBy</code>.</p> * * @return a {@link java.util.ArrayList} object. */ public ArrayList<Card> getEnchantedBy() { return enchantedBy; } /** * <p>Setter for the field <code>enchantedBy</code>.</p> * * @param list a {@link java.util.ArrayList} object. */ public void setEnchantedBy(ArrayList<Card> list) { enchantedBy = list; } /** * <p>Getter for the field <code>enchanting</code>.</p> * * @return a {@link java.util.ArrayList} object. */ public ArrayList<Card> getEnchanting() { return enchanting; } /** * <p>getEnchantingCard.</p> * * @return a {@link forge.Card} object. */ public Card getEnchantingCard() { if (enchanting.size() == 0) return null; return enchanting.get(0); } /** * <p>Setter for the field <code>enchanting</code>.</p> * * @param list a {@link java.util.ArrayList} object. */ public void setEnchanting(ArrayList<Card> list) { enchanting = list; } /** * <p>isEnchanted.</p> * * @return a boolean. */ public boolean isEnchanted() { return enchantedBy.size() != 0; } /** * <p>isEnchanting.</p> * * @return a boolean. */ public boolean isEnchanting() { return enchanting.size() != 0; } /** * <p>addEnchantedBy.</p> * * @param c a {@link forge.Card} object. */ public void addEnchantedBy(Card c) { enchantedBy.add(c); this.updateObservers(); } /** * <p>removeEnchantedBy.</p> * * @param c a {@link forge.Card} object. */ public void removeEnchantedBy(Card c) { enchantedBy.remove(c); this.updateObservers(); } /** * checks to see if this card is enchanted by an aura with a given name * * @param cardName the name of the aura * @return true if this card is enchanted by an aura with the given name, false otherwise */ public boolean isEnchantedBy(String cardName) { ArrayList<Card> allAuras = this.getEnchantedBy(); for (Card aura : allAuras) { if (aura.getName().equals(cardName)) return true; } return false; } /** * <p>addEnchanting.</p> * * @param c a {@link forge.Card} object. */ public void addEnchanting(Card c) { enchanting.add(c); this.updateObservers(); } /** * <p>removeEnchanting.</p> * * @param c a {@link forge.Card} object. */ public void removeEnchanting(Card c) { enchanting.remove(c); this.updateObservers(); } /** * <p>enchantCard.</p> * * @param c a {@link forge.Card} object. */ public void enchantCard(Card c) { enchanting.add(c); c.addEnchantedBy(this); this.enchant(); } /** * <p>unEnchantCard.</p> * * @param c a {@link forge.Card} object. */ public void unEnchantCard(Card c) { this.unEnchant(); enchanting.remove(c); c.removeEnchantedBy(this); } /** * <p>unEnchantAllCards.</p> */ public void unEnchantAllCards() { for (int i = 0; i < enchantedBy.size(); i++) { enchantedBy.get(i).unEnchantCard(this); } } //array size might equal 0, will NEVER be null /** * <p>getAttachedCards.</p> * * @return an array of {@link forge.Card} objects. */ public Card[] getAttachedCards() { Card c[] = new Card[attached.size()]; attached.toArray(c); return c; } /** * <p>hasAttachedCards.</p> * * @return a boolean. */ public boolean hasAttachedCards() { return getAttachedCards().length != 0; } /** * <p>attachCard.</p> * * @param c a {@link forge.Card} object. */ public void attachCard(Card c) { attached.add(c); this.updateObservers(); } /** * <p>unattachCard.</p> * * @param c a {@link forge.Card} object. */ public void unattachCard(Card c) { attached.remove(c); this.updateObservers(); } /** * <p>Setter for the field <code>type</code>.</p> * * @param a a {@link java.util.ArrayList} object. */ public void setType(ArrayList<String> a) { type = new ArrayList<String>(a); } /** * <p>addType.</p> * * @param a a {@link java.lang.String} object. */ public void addType(String a) { type.add(a); this.updateObservers(); } /** * <p>removeType.</p> * * @param a a {@link java.lang.String} object. */ public void removeType(String a) { type.remove(a); this.updateObservers(); } /** * <p>Getter for the field <code>type</code>.</p> * * @return a {@link java.util.ArrayList} object. */ public ArrayList<String> getType() { return new ArrayList<String>(type); } /** * <p>clearAllTypes.</p> * * @return a {@link java.util.ArrayList} object. */ public ArrayList<String> clearAllTypes() { ArrayList<String> originalTypes = new ArrayList<String>(); originalTypes.addAll(type); type.clear(); return originalTypes; } /** * <p>Setter for the field <code>prevType</code>.</p> * * @param a a {@link java.util.ArrayList} object. */ public void setPrevType(ArrayList<String> a) { prevType = new ArrayList<String>(a); } /** * <p>addPrevType.</p> * * @param a a {@link java.lang.String} object. */ public void addPrevType(String a) { prevType.add(a); } /** * <p>removePrevType.</p> * * @param a a {@link java.lang.String} object. */ public void removePrevType(String a) { prevType.remove(a); } /** * <p>Getter for the field <code>prevType</code>.</p> * * @return a {@link java.util.ArrayList} object. */ public ArrayList<String> getPrevType() { return new ArrayList<String>(prevType); } //values that are printed on card /** * <p>Getter for the field <code>baseLoyalty</code>.</p> * * @return a int. */ public int getBaseLoyalty() { return baseLoyalty; } //values that are printed on card /** * <p>Setter for the field <code>baseLoyalty</code>.</p> * * @param n a int. */ public void setBaseLoyalty(int n) { baseLoyalty = n; } //values that are printed on card /** * <p>Getter for the field <code>baseAttack</code>.</p> * * @return a int. */ public int getBaseAttack() { return baseAttack; } /** * <p>Getter for the field <code>baseDefense</code>.</p> * * @return a int. */ public int getBaseDefense() { return baseDefense; } //values that are printed on card /** * <p>Setter for the field <code>baseAttack</code>.</p> * * @param n a int. */ public void setBaseAttack(int n) { baseAttack = n; } /** * <p>Setter for the field <code>baseDefense</code>.</p> * * @param n a int. */ public void setBaseDefense(int n) { baseDefense = n; } //values that are printed on card /** * <p>Getter for the field <code>baseAttackString</code>.</p> * * @return a {@link java.lang.String} object. */ public String getBaseAttackString() { return (null == baseAttackString) ? "" + getBaseAttack() : baseAttackString; } /** * <p>Getter for the field <code>baseDefenseString</code>.</p> * * @return a {@link java.lang.String} object. */ public String getBaseDefenseString() { return (null == baseDefenseString) ? "" + getBaseDefense() : baseDefenseString; } //values that are printed on card /** * <p>Setter for the field <code>baseAttackString</code>.</p> * * @param s a {@link java.lang.String} object. */ public void setBaseAttackString(String s) { baseAttackString = s; this.updateObservers(); } /** * <p>Setter for the field <code>baseDefenseString</code>.</p> * * @param s a {@link java.lang.String} object. */ public void setBaseDefenseString(String s) { baseDefenseString = s; this.updateObservers(); } public int getSetPower() { if (newPT.isEmpty()) return -1; Card_PT latestPT = getLatestPT(); return latestPT.getPower(); } public int getSetToughness() { if (newPT.isEmpty()) return -1; Card_PT latestPT = getLatestPT(); return latestPT.getToughness(); } public Card_PT getLatestPT() { Card_PT latestPT = new Card_PT(-1,-1,0); long max = 0; for (Card_PT pt : newPT) { if (pt.getTimestamp() >= max) { max = pt.getTimestamp(); latestPT = pt; } } return latestPT; } public void addNewPT(int power, int toughness, long timestamp) { newPT.add(new Card_PT(power, toughness, timestamp)); } public void removeNewPT(long timestamp) { for (int i = 0; i < newPT.size(); i++) { Card_PT cardPT = newPT.get(i); if (cardPT.getTimestamp() == timestamp) newPT.remove(cardPT); } } /** * <p>getUnswitchedAttack.</p> * * @return a int. */ public int getUnswitchedAttack() { int total = getBaseAttack(); int setPower = getSetPower(); if(setPower != -1) total = setPower; total += getTempAttackBoost() + getSemiPermanentAttackBoost() + getCounters(Counters.P1P1) + getCounters(Counters.P1P2) + getCounters(Counters.P1P0) - getCounters(Counters.M1M1) + (2 * getCounters(Counters.P2P2) - (2 * getCounters(Counters.M2M1)) - (2 * getCounters(Counters.M2M2)) - getCounters(Counters.M1M0)); return total; } /** * <p>getNetAttack.</p> * * @return a int. */ public int getNetAttack() { if (this.getAmountOfKeyword("CARDNAME's power and toughness are switched") % 2 != 0) return getUnswitchedDefense(); else return getUnswitchedAttack(); } /** * <p>getUnswitchedDefense.</p> * * @return a int. */ public int getUnswitchedDefense() { int total = getBaseDefense(); int setToughness = getSetToughness(); if(setToughness != -1) total = setToughness; total += getTempDefenseBoost() + getSemiPermanentDefenseBoost() + getCounters(Counters.P1P1) + (2 * getCounters(Counters.P1P2)) - getCounters(Counters.M1M1) + getCounters(Counters.P0P1) - (2 * getCounters(Counters.M0M2)) + (2 * getCounters(Counters.P2P2)) - getCounters(Counters.M0M1) - getCounters(Counters.M2M1) - (2 * getCounters(Counters.M2M2)); return total; } /** * <p>getNetDefense.</p> * * @return a int. */ public int getNetDefense() { if (this.getAmountOfKeyword("CARDNAME's power and toughness are switched") % 2 != 0) return getUnswitchedAttack(); else return getUnswitchedDefense(); } //How much combat damage does the card deal /** * <p>getNetCombatDamage.</p> * * @return a int. */ public int getNetCombatDamage() { if (AllZoneUtil.isCardInPlay("Doran, the Siege Tower")) return getNetDefense(); return getNetAttack(); } /** * <p>Setter for the field <code>randomPicture</code>.</p> * * @param n a int. */ public void setRandomPicture(int n) { randomPicture = n; } /** * <p>Getter for the field <code>randomPicture</code>.</p> * * @return a int. */ public int getRandomPicture() { return randomPicture; } /** * <p>addMultiKickerMagnitude.</p> * * @param n a int. */ public void addMultiKickerMagnitude(int n) { multiKickerMagnitude += n; } /** * <p>Setter for the field <code>multiKickerMagnitude</code>.</p> * * @param n a int. */ public void setMultiKickerMagnitude(int n) { multiKickerMagnitude = n; } /** * <p>Getter for the field <code>multiKickerMagnitude</code>.</p> * * @return a int. */ public int getMultiKickerMagnitude() { return multiKickerMagnitude; } /** * <p>addReplicateMagnitude.</p> * * @param n a int. */ public void addReplicateMagnitude(int n) { replicateMagnitude += n; } /** * <p>Setter for the field <code>replicateMagnitude</code>.</p> * * @param n a int. */ public void setReplicateMagnitude(int n) { replicateMagnitude = n; } /** * <p>Getter for the field <code>replicateMagnitude</code>.</p> * * @return a int. */ public int getReplicateMagnitude() { return replicateMagnitude; } //for cards like Giant Growth, etc. /** * <p>Getter for the field <code>tempAttackBoost</code>.</p> * * @return a int. */ public int getTempAttackBoost() { return tempAttackBoost; } /** * <p>Getter for the field <code>tempDefenseBoost</code>.</p> * * @return a int. */ public int getTempDefenseBoost() { return tempDefenseBoost; } /** * <p>addTempAttackBoost.</p> * * @param n a int. */ public void addTempAttackBoost(int n) { tempAttackBoost += n; this.updateObservers(); } /** * <p>addTempDefenseBoost.</p> * * @param n a int. */ public void addTempDefenseBoost(int n) { tempDefenseBoost += n; this.updateObservers(); } /** * <p>Setter for the field <code>tempAttackBoost</code>.</p> * * @param n a int. */ public void setTempAttackBoost(int n) { tempAttackBoost = n; this.updateObservers(); } /** * <p>Setter for the field <code>tempDefenseBoost</code>.</p> * * @param n a int. */ public void setTempDefenseBoost(int n) { tempDefenseBoost = n; this.updateObservers(); } //for cards like Glorious Anthem, etc. /** * <p>Getter for the field <code>semiPermanentAttackBoost</code>.</p> * * @return a int. */ public int getSemiPermanentAttackBoost() { return semiPermanentAttackBoost; } /** * <p>Getter for the field <code>semiPermanentDefenseBoost</code>.</p> * * @return a int. */ public int getSemiPermanentDefenseBoost() { return semiPermanentDefenseBoost; } /** * <p>addSemiPermanentAttackBoost.</p> * * @param n a int. */ public void addSemiPermanentAttackBoost(int n) { semiPermanentAttackBoost += n; } /** * <p>addSemiPermanentDefenseBoost.</p> * * @param n a int. */ public void addSemiPermanentDefenseBoost(int n) { semiPermanentDefenseBoost += n; } /** * <p>Setter for the field <code>semiPermanentAttackBoost</code>.</p> * * @param n a int. */ public void setSemiPermanentAttackBoost(int n) { semiPermanentAttackBoost = n; } /** * <p>Setter for the field <code>semiPermanentDefenseBoost</code>.</p> * * @param n a int. */ public void setSemiPermanentDefenseBoost(int n) { semiPermanentDefenseBoost = n; } /** * <p>isUntapped.</p> * * @return a boolean. */ public boolean isUntapped() { return !tapped; } /** * <p>isTapped.</p> * * @return a boolean. */ public boolean isTapped() { return tapped; } /** * <p>Setter for the field <code>tapped</code>.</p> * * @param b a boolean. */ public void setTapped(boolean b) { tapped = b; updateObservers(); } /** * <p>tap.</p> */ public void tap() { if (isUntapped()) { //Run triggers Map<String, Object> runParams = new TreeMap<String, Object>(); runParams.put("Card", this); AllZone.getTriggerHandler().runTrigger("Taps", runParams); } setTapped(true); } /** * <p>untap.</p> */ public void untap() { if (isTapped()) { //Run triggers Map<String, Object> runParams = new TreeMap<String, Object>(); runParams.put("Card", this); AllZone.getTriggerHandler().runTrigger("Untaps", runParams); } for (Command var : untapCommandList) { var.execute(); } setTapped(false); } /** * <p>isUnCastable.</p> * * @return a boolean. */ public boolean isUnCastable() { return unCastable; } /** * <p>Setter for the field <code>unCastable</code>.</p> * * @param b a boolean. */ public void setUnCastable(boolean b) { unCastable = b; updateObservers(); } //keywords are like flying, fear, first strike, etc... /** * <p>getKeyword.</p> * * @return a {@link java.util.ArrayList} object. */ public ArrayList<String> getKeyword() { ArrayList<String> a1 = new ArrayList<String>(getIntrinsicKeyword()); ArrayList<String> a2 = new ArrayList<String>(getExtrinsicKeyword()); ArrayList<String> a3 = new ArrayList<String>(getOtherExtrinsicKeyword()); ArrayList<String> a4 = new ArrayList<String>(getHiddenExtrinsicKeyword()); a1.addAll(a2); a1.addAll(a3); a1.addAll(a4); // SOL Changes for Mana //for(Ability_Mana sa:getManaAbility()) // if(sa.isBasic()) a1.add((sa).orig); return a1; } //keywords are like flying, fear, first strike, etc... // Hidden keywords will be left out /** * <p>getUnhiddenKeyword.</p> * * @return a {@link java.util.ArrayList} object. */ public ArrayList<String> getUnhiddenKeyword() { ArrayList<String> a1 = new ArrayList<String>(getIntrinsicKeyword()); ArrayList<String> a2 = new ArrayList<String>(getExtrinsicKeyword()); ArrayList<String> a3 = new ArrayList<String>(getOtherExtrinsicKeyword()); a1.addAll(a2); a1.addAll(a3); // SOL Changes for Mana //for(Ability_Mana sa:getManaAbility()) // if(sa.isBasic()) a1.add((sa).orig); return a1; } /** * <p>getIntrinsicAbilities.</p> * * @return a {@link java.util.ArrayList} object. */ public ArrayList<String> getIntrinsicAbilities() { return intrinsicAbility; } /** * <p>Getter for the field <code>intrinsicKeyword</code>.</p> * * @return a {@link java.util.ArrayList} object. */ public ArrayList<String> getIntrinsicKeyword() { return new ArrayList<String>(intrinsicKeyword); } /** * <p>clearIntrinsicKeyword.</p> */ public void clearIntrinsicKeyword() { intrinsicKeyword.clear(); } /** * <p>Setter for the field <code>intrinsicKeyword</code>.</p> * * @param a a {@link java.util.ArrayList} object. */ public void setIntrinsicKeyword(ArrayList<String> a) { intrinsicKeyword = new ArrayList<String>(a); this.updateObservers(); } /** * <p>clearAllKeywords.</p> */ public void clearAllKeywords() { intrinsicKeyword.clear(); extrinsicKeyword.clear(); otherExtrinsicKeyword.clear(); HiddenExtrinsicKeyword.clear(); //Hidden keywords won't be displayed on the card } /** * <p>setIntrinsicAbilities.</p> * * @param a a {@link java.util.ArrayList} object. */ public void setIntrinsicAbilities(ArrayList<String> a) { intrinsicAbility = new ArrayList<String>(a); } /** * <p>addIntrinsicKeyword.</p> * * @param s a {@link java.lang.String} object. */ public void addIntrinsicKeyword(String s) { if (s.trim().length() != 0) intrinsicKeyword.add(s); //intrinsicKeyword.add((getName().trim().length()== 0 ? s :s.replaceAll(getName(), "CARDNAME"))); } /** * <p>addIntrinsicAbility.</p> * * @param s a {@link java.lang.String} object. */ public void addIntrinsicAbility(String s) { if (s.trim().length() != 0) intrinsicAbility.add(s); } /** * <p>addNonStackingIntrinsicKeyword.</p> * * @param s a {@link java.lang.String} object. */ public void addNonStackingIntrinsicKeyword(String s) { if (!getIntrinsicKeyword().contains(s) && s.trim().length() != 0) { intrinsicKeyword.add((getName().trim().length() == 0 ? s : s.replaceAll(getName(), "CARDNAME"))); } } /** * <p>removeIntrinsicKeyword.</p> * * @param s a {@link java.lang.String} object. */ public void removeIntrinsicKeyword(String s) { intrinsicKeyword.remove(s); this.updateObservers(); } /** * <p>getIntrinsicKeywordSize.</p> * * @return a int. */ public int getIntrinsicKeywordSize() { return intrinsicKeyword.size(); } /** * <p>Getter for the field <code>extrinsicKeyword</code>.</p> * * @return a {@link java.util.ArrayList} object. */ public ArrayList<String> getExtrinsicKeyword() { return new ArrayList<String>(extrinsicKeyword); } /** * <p>Setter for the field <code>extrinsicKeyword</code>.</p> * * @param a a {@link java.util.ArrayList} object. */ public void setExtrinsicKeyword(ArrayList<String> a) { extrinsicKeyword = new ArrayList<String>(a); this.updateObservers(); } /** * <p>addExtrinsicKeyword.</p> * * @param s a {@link java.lang.String} object. */ public void addExtrinsicKeyword(String s) { //if(!hasKeyword(s)){ if (s.startsWith("HIDDEN")) addHiddenExtrinsicKeyword(s); else extrinsicKeyword.add(s); //extrinsicKeyword.add((getName().trim().length()==0 ? s :s.replaceAll(getName(), "CARDNAME"))); //} } /** * <p>addStackingExtrinsicKeyword.</p> * * @param s a {@link java.lang.String} object. */ public void addStackingExtrinsicKeyword(String s) { if (s.startsWith("HIDDEN")) addHiddenExtrinsicKeyword(s); else extrinsicKeyword.add(s); } /** * <p>removeExtrinsicKeyword.</p> * * @param s a {@link java.lang.String} object. */ public void removeExtrinsicKeyword(String s) { if (s.startsWith("HIDDEN")) removeHiddenExtrinsicKeyword(s); else extrinsicKeyword.remove(s); this.updateObservers(); } /** * <p>getExtrinsicKeywordSize.</p> * * @return a int. */ public int getExtrinsicKeywordSize() { return extrinsicKeyword.size(); } /** * <p>Getter for the field <code>otherExtrinsicKeyword</code>.</p> * * @return a {@link java.util.ArrayList} object. */ public ArrayList<String> getOtherExtrinsicKeyword() { return new ArrayList<String>(otherExtrinsicKeyword); } /** * <p>Setter for the field <code>otherExtrinsicKeyword</code>.</p> * * @param a a {@link java.util.ArrayList} object. */ public void setOtherExtrinsicKeyword(ArrayList<String> a) { otherExtrinsicKeyword = new ArrayList<String>(a); this.updateObservers(); } /** * <p>addOtherExtrinsicKeyword.</p> * * @param s a {@link java.lang.String} object. */ public void addOtherExtrinsicKeyword(String s) { otherExtrinsicKeyword.add((getName().trim().length() == 0 ? s : s.replaceAll(getName(), "CARDNAME"))); } /** * <p>addStackingOtherExtrinsicKeyword.</p> * * @param s a {@link java.lang.String} object. */ public void addStackingOtherExtrinsicKeyword(String s) { extrinsicKeyword.add(s); } /** * <p>removeOtherExtrinsicKeyword.</p> * * @param s a {@link java.lang.String} object. */ public void removeOtherExtrinsicKeyword(String s) { otherExtrinsicKeyword.remove(s); this.updateObservers(); } /** * <p>getOtherExtrinsicKeywordSize.</p> * * @return a int. */ public int getOtherExtrinsicKeywordSize() { return otherExtrinsicKeyword.size(); } /** * <p>Getter for the field <code>prevIntrinsicKeyword</code>.</p> * * @return a {@link java.util.ArrayList} object. */ public ArrayList<String> getPrevIntrinsicKeyword() { return new ArrayList<String>(prevIntrinsicKeyword); } /** * <p>Setter for the field <code>prevIntrinsicKeyword</code>.</p> * * @param a a {@link java.util.ArrayList} object. */ public void setPrevIntrinsicKeyword(ArrayList<String> a) { prevIntrinsicKeyword = new ArrayList<String>(a); this.updateObservers(); } /** * <p>addPrevIntrinsicKeyword.</p> * * @param s a {@link java.lang.String} object. */ public void addPrevIntrinsicKeyword(String s) { prevIntrinsicKeyword.add(s); } /** * <p>removePrevIntrinsicKeyword.</p> * * @param s a {@link java.lang.String} object. */ public void removePrevIntrinsicKeyword(String s) { prevIntrinsicKeyword.remove(s); this.updateObservers(); } /** * <p>getPrevIntrinsicKeywordSize.</p> * * @return a int. */ public int getPrevIntrinsicKeywordSize() { return prevIntrinsicKeyword.size(); } // Hidden Keywords will be returned without the indicator HIDDEN /** * <p>getHiddenExtrinsicKeyword.</p> * * @return a {@link java.util.ArrayList} object. */ public ArrayList<String> getHiddenExtrinsicKeyword() { ArrayList<String> keywords = new ArrayList<String>(); for (int i = 0; i < HiddenExtrinsicKeyword.size(); i++) { String keyword = HiddenExtrinsicKeyword.get(i); keywords.add(keyword.substring(7)); } return keywords; } /** * <p>addHiddenExtrinsicKeyword.</p> * * @param s a {@link java.lang.String} object. */ public void addHiddenExtrinsicKeyword(String s) { HiddenExtrinsicKeyword.add(s); } /** * <p>removeHiddenExtrinsicKeyword.</p> * * @param s a {@link java.lang.String} object. */ public void removeHiddenExtrinsicKeyword(String s) { HiddenExtrinsicKeyword.remove(s); //this.updateObservers(); } /** * <p>setStaticAbilityStrings.</p> * * @param a a {@link java.util.ArrayList} object. */ public void setStaticAbilityStrings(ArrayList<String> a) { staticAbilityStrings = new ArrayList<String>(a); } public ArrayList<String> getStaticAbilityStrings() { return staticAbilityStrings; } /** * <p>addStaticAbilityStrings.</p> * * @param s a {@link java.lang.String} object. */ public void addStaticAbilityString(String s) { if (s.trim().length() != 0) staticAbilityStrings.add(s); } public void setStaticAbilities(ArrayList<StaticAbility> a) { staticAbilities = new ArrayList<StaticAbility>(a); } public ArrayList<StaticAbility> getStaticAbilities() { return new ArrayList<StaticAbility>(staticAbilities); } public void addStaticAbility(String s) { if (s.trim().length() != 0) { StaticAbility stAb = new StaticAbility(s,this); staticAbilities.add(stAb); } } /** * <p>isPermanent.</p> * * @return a boolean. */ public boolean isPermanent() { return !(isInstant() || isSorcery() || isImmutable()); } /** * <p>isSpell.</p> * * @return a boolean. */ public boolean isSpell() { return (isInstant() || isSorcery() || (isAura() && !AllZoneUtil.getCardsInPlay().contains(this))); } /** * <p>isCreature.</p> * * @return a boolean. */ public boolean isCreature() { return type.contains("Creature"); } /** * <p>isWall.</p> * * @return a boolean. */ public boolean isWall() { return type.contains("Wall"); } /** * <p>isBasicLand.</p> * * @return a boolean. */ public boolean isBasicLand() { return type.contains("Basic"); } /** * <p>isLand.</p> * * @return a boolean. */ public boolean isLand() { return type.contains("Land"); } /** * <p>isSorcery.</p> * * @return a boolean. */ public boolean isSorcery() { return type.contains("Sorcery"); } /** * <p>isInstant.</p> * * @return a boolean. */ public boolean isInstant() { return type.contains("Instant"); } /** * <p>isArtifact.</p> * * @return a boolean. */ public boolean isArtifact() { return type.contains("Artifact"); } /** * <p>isEquipment.</p> * * @return a boolean. */ public boolean isEquipment() { return type.contains("Equipment"); } /** * <p>isPlaneswalker.</p> * * @return a boolean. */ public boolean isPlaneswalker() { return type.contains("Planeswalker"); } /** * <p>isEmblem.</p> * * @return a boolean. */ public boolean isEmblem() { return type.contains("Emblem"); } /** * <p>isTribal.</p> * * @return a boolean. */ public boolean isTribal() { return type.contains("Tribal"); } /** * <p>isSnow.</p> * * @return a boolean. */ public boolean isSnow() { return type.contains("Snow"); } //global and local enchantments /** * <p>isEnchantment.</p> * * @return a boolean. */ public boolean isEnchantment() { return typeContains("Enchantment"); } /** * <p>isAura.</p> * * @return a boolean. */ public boolean isAura() { return typeContains("Aura"); } /** * <p>isGlobalEnchantment.</p> * * @return a boolean. */ public boolean isGlobalEnchantment() { return typeContains("Enchantment") && (!isAura()); } private boolean typeContains(String s) { Iterator<?> it = this.getType().iterator(); while (it.hasNext()) if (it.next().toString().startsWith(s)) return true; return false; } /** * <p>Setter for the field <code>uniqueNumber</code>.</p> * * @param n a int. */ public void setUniqueNumber(int n) { uniqueNumber = n; this.updateObservers(); } /** * <p>Getter for the field <code>uniqueNumber</code>.</p> * * @return a int. */ public int getUniqueNumber() { return uniqueNumber; } /** * <p>Setter for the field <code>value</code>.</p> * * @param n a long. */ public void setValue(long n) { value = n; } /** * <p>Getter for the field <code>value</code>.</p> * * @return a long. */ public long getValue() { return value; } /** {@inheritDoc} */ @Override public int compareTo(Card that) { /* * Return a negative integer of this < that, * a positive integer if this > that, * and zero otherwise. */ if (that == null) { /* * "Here we can arbitrarily decide that all non-null Cards are * `greater than' null Cards. It doesn't really matter what we * return in this case, as long as it is consistent. I rather think * of null as being lowly." --Braids */ return +1; } else if (getUniqueNumber() > that.getUniqueNumber()) { return +1; } else if (getUniqueNumber() < that.getUniqueNumber()) { return -1; } else { return 0; } } /** {@inheritDoc} */ @Override public boolean equals(Object o) { if (o instanceof Card) { Card c = (Card) o; int a = getUniqueNumber(); int b = c.getUniqueNumber(); return (a == b); } return false; } /** {@inheritDoc} */ @Override public int hashCode() { return getUniqueNumber(); } /** {@inheritDoc} */ @Override public String toString() { return this.getName() + " (" + this.getUniqueNumber() + ")"; } /** * <p>hasFlashback.</p> * * @return a boolean. */ public boolean hasFlashback() { return flashback; } /** * <p>Setter for the field <code>flashback</code>.</p> * * @param b a boolean. */ public void setFlashback(boolean b) { flashback = b; } /** * <p>hasUnearth.</p> * * @return a boolean. */ public boolean hasUnearth() { return unearth; } /** * <p>Setter for the field <code>unearth</code>.</p> * * @param b a boolean. */ public void setUnearth(boolean b) { unearth = b; } /** * <p>isUnearthed.</p> * * @return a boolean. */ public boolean isUnearthed() { return unearthed; } /** * <p>Setter for the field <code>unearthed</code>.</p> * * @param b a boolean. */ public void setUnearthed(boolean b) { unearthed = b; } /** * <p>hasMadness.</p> * * @return a boolean. */ public boolean hasMadness() { return madness; } /** * <p>Setter for the field <code>madness</code>.</p> * * @param b a boolean. */ public void setMadness(boolean b) { madness = b; } /** * <p>Getter for the field <code>madnessCost</code>.</p> * * @return a {@link java.lang.String} object. */ public String getMadnessCost() { return madnessCost; } /** * <p>Setter for the field <code>madnessCost</code>.</p> * * @param cost a {@link java.lang.String} object. */ public void setMadnessCost(String cost) { madnessCost = cost; } /** * <p>hasSuspend.</p> * * @return a boolean. */ public boolean hasSuspend() { return suspend; } /** * <p>Setter for the field <code>suspend</code>.</p> * * @param b a boolean. */ public void setSuspend(boolean b) { suspend = b; } /** * <p>wasSuspendCast.</p> * * @return a boolean. */ public boolean wasSuspendCast() { return suspendCast; } /** * <p>Setter for the field <code>suspendCast</code>.</p> * * @param b a boolean. */ public void setSuspendCast(boolean b) { suspendCast = b; } /** * <p>Setter for the field <code>kicked</code>.</p> * * @param b a boolean. */ public void setKicked(boolean b) { kicked = b; } /** * <p>isKicked.</p> * * @return a boolean. */ public boolean isKicked() { return kicked; } /** * <p>Setter for the field <code>reflectedLand</code>.</p> * * @param b a boolean. */ public void setReflectedLand(boolean b) { reflectedLand = b; } /** * <p>isReflectedLand.</p> * * @return a boolean. */ public boolean isReflectedLand() { return reflectedLand; } /** * <p>hasKeyword.</p> * * @param keyword a {@link java.lang.String} object. * @return a boolean. */ public boolean hasKeyword(String keyword) { return getKeyword().contains(keyword); } /** * <p>hasStartOfKeyword.</p> * * @param keyword a {@link java.lang.String} object. * @return a boolean. */ public boolean hasStartOfKeyword(String keyword) { ArrayList<String> a = getKeyword(); for (int i = 0; i < a.size(); i++) if (a.get(i).toString().startsWith(keyword)) return true; return false; } /** * <p>getKeywordPosition.</p> * * @param k a {@link java.lang.String} object. * @return a int. */ public int getKeywordPosition(String k) { ArrayList<String> a = getKeyword(); for (int i = 0; i < a.size(); i++) if (a.get(i).toString().startsWith(k)) return i; return -1; } /** * <p>keywordsContain.</p> * * @param keyword a {@link java.lang.String} object. * @return a boolean. */ public boolean keywordsContain(String keyword) { ArrayList<String> a = getKeyword(); for (int i = 0; i < a.size(); i++) if (a.get(i).toString().contains(keyword)) return true; return false; } /** * <p>hasAnyKeyword.</p> * * @param keywords an array of {@link java.lang.String} objects. * @return a boolean. */ public boolean hasAnyKeyword(String keywords[]) { for (int i = 0; i < keywords.length; i++) if (hasKeyword(keywords[i])) return true; return false; } /** * <p>hasAnyKeyword.</p> * * @param keywords a {@link java.util.ArrayList} object. * @return a boolean. */ public boolean hasAnyKeyword(ArrayList<String> keywords) { for (int i = 0; i < keywords.size(); i++) if (hasKeyword(keywords.get(i))) return true; return false; } //This counts the number of instances of a keyword a card has /** * <p>getAmountOfKeyword.</p> * * @param k a {@link java.lang.String} object. * @return a int. */ public int getAmountOfKeyword(String k) { int count = 0; ArrayList<String> keywords = getKeyword(); for (int j = 0; j < keywords.size(); j++) { if (keywords.get(j).equals(k)) count++; } return count; } // This is for keywords with a number like Bushido, Annihilator and Rampage. It returns the total. /** * <p>getKeywordMagnitude.</p> * * @param k a {@link java.lang.String} object. * @return a int. */ public int getKeywordMagnitude(String k) { int count = 0; ArrayList<String> keywords = getKeyword(); for (String kw : keywords) { if (kw.startsWith(k)) { String[] parse = kw.split(" "); String s = parse[1]; count += Integer.parseInt(s); } } return count; } private String toMixedCase(String s) { if (s.equals("")) return s; StringBuilder sb = new StringBuilder(); // to handle hyphenated Types String[] types = s.split("-"); for (int i = 0; i < types.length; i++) { if (i != 0) sb.append("-"); sb.append(types[i].substring(0, 1).toUpperCase()); sb.append(types[i].substring(1).toLowerCase()); } return sb.toString(); } //usable to check for changelings /** * <p>isType.</p> * * @param cardType a {@link java.lang.String} object. * @return a boolean. */ public boolean isType(String cardType) { cardType = toMixedCase(cardType); if (type.contains(cardType) || ((isCreature() || isTribal()) && CardUtil.isACreatureType(cardType) && hasKeyword("Changeling"))) return true; return false; } /** * <p>isValidCard.</p> * Takes an array of arguments like Permanent.Blue+withFlying, only one of them has to be true * * @param Restrictions an array of {@link java.lang.String} objects. * @param sourceController a {@link forge.Player} object. * @param source a {@link forge.Card} object. * @return a boolean. */ public boolean isValidCard(final String Restrictions[], final Player sourceController, final Card source) { if (getName().equals("Mana Pool") || isImmutable()) return false; for (int i = 0; i < Restrictions.length; i++) { if (isValid(Restrictions[i], sourceController, source)) return true; } return false; }//isValidCard // Takes one argument like Permanent.Blue+withFlying /** * <p>isValid.</p> * * @param Restriction a {@link java.lang.String} object. * @param sourceController a {@link forge.Player} object. * @param source a {@link forge.Card} object. * @return a boolean. */ public boolean isValid(final String Restriction, final Player sourceController, final Card source) { if (getName().equals("Mana Pool") || isImmutable()) return false; if (Restriction.equals("False")) return false; String incR[] = Restriction.split("\\."); // Inclusive restrictions are Card types if (incR[0].equals("Spell") && !isSpell()) return false; if (incR[0].equals("Permanent") && (isInstant() || isSorcery())) return false; if (!incR[0].equals("card") && !incR[0].equals("Card") && !incR[0].equals("Spell") && !incR[0].equals("Permanent") && !(isType(incR[0]))) return false; //Check for wrong type if (incR.length > 1) { final String excR = incR[1]; String exR[] = excR.split("\\+"); // Exclusive Restrictions are ... for (int j = 0; j < exR.length; j++) if (hasProperty(exR[j], sourceController, source) == false) return false; } return true; }//isValidCard(String Restriction) // Takes arguments like Blue or withFlying /** * <p>hasProperty.</p> * * @param Property a {@link java.lang.String} object. * @param sourceController a {@link forge.Player} object. * @param source a {@link forge.Card} object. * @return a boolean. */ public boolean hasProperty(String Property, final Player sourceController, final Card source) { //by name can also have color names, so needs to happen before colors. if (Property.startsWith("named")) { if (!getName().equals(Property.substring(5))) return false; } else if (Property.startsWith("notnamed")) { if (getName().equals(Property.substring(8))) return false; } else if (Property.startsWith("sameName")) { if (!getName().equals(source.getName())) return false; } // ... Card colors else if (Property.contains("White") || Property.contains("Blue") || Property.contains("Black") || Property.contains("Red") || Property.contains("Green") || Property.contains("Colorless")) { if (Property.startsWith("non")) { if (CardUtil.getColors(this).contains(Property.substring(3).toLowerCase())) return false; } else if (!CardUtil.getColors(this).contains(Property.toLowerCase())) return false; } else if (Property.contains("MultiColor")) // ... Card is multicolored { if (Property.startsWith("non") && (CardUtil.getColors(this).size() > 1)) return false; if (!Property.startsWith("non") && (CardUtil.getColors(this).size() <= 1)) return false; } else if (Property.contains("MonoColor")) // ... Card is monocolored { if (Property.startsWith("non") && (CardUtil.getColors(this).size() == 1 && !isColorless())) return false; if (!Property.startsWith("non") && (CardUtil.getColors(this).size() > 1 || isColorless())) return false; } else if (Property.startsWith("YouCtrl")) { if (!getController().isPlayer(sourceController)) return false; } else if (Property.startsWith("YouDontCtrl")) { if (getController().isPlayer(sourceController)) return false; } else if (Property.startsWith("YouOwn")) { if (!getOwner().isPlayer(sourceController)) return false; } else if (Property.startsWith("YouDontOwn")) { if (getOwner().isPlayer(sourceController)) return false; } else if (Property.startsWith("ControllerControls")) { String type = Property.substring(18); CardList list = AllZoneUtil.getPlayerCardsInPlay(getController()); if (list.getType(type).isEmpty()) return false; } else if (Property.startsWith("Other")) { if (this.equals(source)) return false; } else if (Property.startsWith("Self")) { if (!this.equals(source)) return false; } else if (Property.startsWith("AttachedBy")) { if (!equippedBy.contains(source) && !enchantedBy.contains(source)) return false; } else if (Property.startsWith("Attached")) { if (!equipping.contains(source) && !enchanting.contains(source)) return false; } else if (Property.startsWith("EnchantedBy")) { if (!enchantedBy.contains(source)) return false; } else if (Property.startsWith("Enchanted")) { if (!enchanting.contains(source)) return false; } else if (Property.startsWith("EquippedBy")) { if (!equippedBy.contains(source)) return false; } else if (Property.startsWith("Equipped")) { if (!equipping.contains(source)) return false; } else if (Property.startsWith("Cloned")) { if (cloneOrigin == null || !cloneOrigin.equals(source)) return false; } else if (Property.startsWith("DamagedBy")) { if (!receivedDamageFromThisTurn.containsKey(source)) return false; } else if (Property.startsWith("Damaged")) { if (!dealtDamageToThisTurn.containsKey(source)) return false; } else if (Property.startsWith("SharesColorWith")) { if (!sharesColorWith(source)) return false; } else if (Property.startsWith("with")) // ... Card keywords { if (Property.startsWith("without") && hasStartOfKeyword(Property.substring(7))) return false; if (!Property.startsWith("without") && !hasStartOfKeyword(Property.substring(4))) return false; } else if (Property.startsWith("tapped")) { if (!isTapped()) return false; } else if (Property.startsWith("untapped")) { if (!isUntapped()) return false; } else if (Property.startsWith("faceDown")) { if (!isFaceDown()) return false; } else if (Property.startsWith("hasLevelUp")) { if (!hasLevelUp()) return false; } else if (Property.startsWith("enteredBattlefieldThisTurn")) { if (!(getTurnInZone() == AllZone.getPhase().getTurn())) return false; } else if (Property.startsWith("dealtDamageToYouThisTurn")) { if (!(dealtDmgToHumanThisTurn && getController().isPlayer(AllZone.getComputerPlayer())) && !(dealtDmgToComputerThisTurn && getController().isPlayer(AllZone.getHumanPlayer()))) return false; } else if (Property.startsWith("wasDealtDamageThisTurn")) { if ((getReceivedDamageFromThisTurn().keySet()).isEmpty()) return false; } else if (Property.startsWith("enchanted")) { if (!isEnchanted()) return false; } else if (Property.startsWith("unenchanted")) { if (isEnchanted()) return false; } else if (Property.startsWith("enchanting")) { if (!isEnchanting()) return false; } else if (Property.startsWith("equipped")) { if (!isEquipped()) return false; } else if (Property.startsWith("unequipped")) { if (isEquipped()) return false; } else if (Property.startsWith("equipping")) { if (!isEquipping()) return false; } else if (Property.startsWith("token")) { if (!isToken()) return false; } else if (Property.startsWith("nonToken")) { if (isToken()) return false; } else if (Property.startsWith("power") || // 8/10 Property.startsWith("toughness") || Property.startsWith("cmc")) { int x = 0; int y = 0; int z = 0; if (Property.startsWith("power")) { z = 7; y = getNetAttack(); } else if (Property.startsWith("toughness")) { z = 11; y = getNetDefense(); } else if (Property.startsWith("cmc")) { z = 5; y = getCMC(); } if (Property.substring(z).equals("X")) { x = CardFactoryUtil.xCount(source, source.getSVar("X")); } else if (Property.substring(z).equals("Y")) { x = CardFactoryUtil.xCount(source, source.getSVar("Y")); } else x = Integer.parseInt(Property.substring(z)); if (!AllZoneUtil.compare(y, Property, x)) return false; } // syntax example: countersGE9 P1P1 or countersLT12TIME (greater number than 99 not supported) /* * slapshot5 - fair warning, you cannot use numbers with 2 digits (greater number than 9 not supported * you can use X and the SVar:X:Number$12 to get two digits. This will need a better fix, and I have the * beginnings of a regex below */ else if (Property.startsWith("counters")) { /* Pattern p = Pattern.compile("[a-z]*[A-Z][A-Z][X0-9]+.*$"); String[] parse = ??? System.out.println("Parsing completed of: "+Property); for(int i = 0; i < parse.length; i++) { System.out.println("parse["+i+"]: "+parse[i]); }*/ // TODO: get a working regex out of this pattern so the amount of digits doesn't matter int number = 0; if (Property.substring(10, 11).equals("X")) number = CardFactoryUtil.xCount(source, getSVar("X")); else if (Property.substring(10, 11).equals("Y")) number = CardFactoryUtil.xCount(source, getSVar("Y")); else number = Integer.parseInt(Property.substring(10, 11)); String type = Property.substring(11); String comparator = Property.substring(8, 10); // comparator = EQ, LE, GE etc. int actualnumber = getCounters(Counters.getType(type)); if (!AllZoneUtil.compare(actualnumber, comparator, number)) return false; } else if (Property.startsWith("attacking")) { if (!isAttacking()) return false; } else if (Property.startsWith("notattacking")) { if (isAttacking()) return false; } else if (Property.equals("blocking")) { if (!isBlocking()) return false; } else if (Property.startsWith("blockingSource")) { if (!isBlocking(source)) return false; } else if (Property.startsWith("notblocking")) { if (isBlocking()) return false; } else if (Property.startsWith("blocked")) { if (!AllZone.getCombat().isBlocked(this)) return false; } else if (Property.startsWith("blockedBySource")) { if (!isBlockedBy(source)) return false; } else if (Property.startsWith("unblocked")) { if (!AllZone.getCombat().isUnblocked(this)) return false; } else if (Property.startsWith("kicked")) { if (!isKicked()) return false; } else if (Property.startsWith("notkicked")) { if (isKicked()) return false; } else if (Property.startsWith("evoked")) { if (!isEvoked()) return false; } else if (Property.equals("HasDevoured")) { if(devouredCards.size() == 0) return false; } else if (Property.equals("HasNotDevoured")) { if(devouredCards.size() != 0) return false; } else if (Property.startsWith("non")) // ... Other Card types { if (isType(Property.substring(3))) return false; } else if (Property.equals("CostsPhyrexianMana")) { if (!manaCost.contains("P")) return false; } else if (Property.equals("IsRemembered")) { if(!source.getRemembered().contains(this)) return false; } else { if (Property.equals("ChosenType")) { if (!isType(source.getChosenType())) return false; } else { if (!isType(Property)) return false; } } return true; }//hasProperty /** * <p>setImmutable.</p> * * @param isImmutable a boolean. */ public void setImmutable(boolean isImmutable) { this.isImmutable = isImmutable; } /** * <p>isImmutable.</p> * * @return a boolean. */ public boolean isImmutable() { return isImmutable; } /* * there are easy checkers for Color. The CardUtil functions should * be made part of the Card class, so calling out is not necessary */ /** * <p>isColor.</p> * * @param col a {@link java.lang.String} object. * @return a boolean. */ public boolean isColor(String col) { return CardUtil.getColors(this).contains(col); } /** * <p>isBlack.</p> * * @return a boolean. */ public boolean isBlack() { return CardUtil.getColors(this).contains(Constant.Color.Black); } /** * <p>isBlue.</p> * * @return a boolean. */ public boolean isBlue() { return CardUtil.getColors(this).contains(Constant.Color.Blue); } /** * <p>isRed.</p> * * @return a boolean. */ public boolean isRed() { return CardUtil.getColors(this).contains(Constant.Color.Red); } /** * <p>isGreen.</p> * * @return a boolean. */ public boolean isGreen() { return CardUtil.getColors(this).contains(Constant.Color.Green); } /** * <p>isWhite.</p> * * @return a boolean. */ public boolean isWhite() { return CardUtil.getColors(this).contains(Constant.Color.White); } /** * <p>isColorless.</p> * * @return a boolean. */ public boolean isColorless() { return CardUtil.getColors(this).contains(Constant.Color.Colorless); } /** * <p>sharesColorWith.</p> * * @param c1 a {@link forge.Card} object. * @return a boolean. */ public boolean sharesColorWith(final Card c1) { boolean shares = false; shares |= (isBlack() && c1.isBlack()); shares |= (isBlue() && c1.isBlue()); shares |= (isGreen() && c1.isGreen()); shares |= (isRed() && c1.isRed()); shares |= (isWhite() && c1.isWhite()); return shares; } /** * <p>isAttacking.</p> * * @return a boolean. */ public boolean isAttacking() { return AllZone.getCombat().isAttacking(this); } /** * <p>isBlocking.</p> * * @return a boolean. */ public boolean isBlocking() { CardList blockers = AllZone.getCombat().getAllBlockers(); return blockers.contains(this); } /** * <p>isBlocking.</p> * * @param attacker a {@link forge.Card} object. * @return a boolean. */ public boolean isBlocking(Card attacker) { return attacker.equals(AllZone.getCombat().getAttackerBlockedBy(this)); } /** * <p>isBlockedBy.</p> * * @param blocker a {@link forge.Card} object. * @return a boolean. */ public boolean isBlockedBy(Card blocker) { return this.equals(AllZone.getCombat().getAttackerBlockedBy(blocker)); } /////////////////////////// // // Damage code // ////////////////////////// //all damage to cards is now handled in Card.java, no longer AllZone.getGameAction()... /** * <p>addReceivedDamageFromThisTurn.</p> * * @param c a {@link forge.Card} object. * @param damage a int. */ public void addReceivedDamageFromThisTurn(Card c, int damage) { receivedDamageFromThisTurn.put(c, damage); } /** * <p>Setter for the field <code>receivedDamageFromThisTurn</code>.</p> * * @param receivedDamageList a Map object. */ public void setReceivedDamageFromThisTurn(Map<Card, Integer> receivedDamageList) { receivedDamageFromThisTurn = receivedDamageList; } /** * <p>Getter for the field <code>receivedDamageFromThisTurn</code>.</p> * * @return a Map object. */ public Map<Card, Integer> getReceivedDamageFromThisTurn() { return receivedDamageFromThisTurn; } /** * <p>resetReceivedDamageFromThisTurn.</p> */ public void resetReceivedDamageFromThisTurn() { receivedDamageFromThisTurn.clear(); } /** * <p>addDealtDamageToThisTurn.</p> * * @param c a {@link forge.Card} object. * @param damage a int. */ public void addDealtDamageToThisTurn(Card c, int damage) { dealtDamageToThisTurn.put(c, damage); } /** * <p>Setter for the field <code>dealtDamageToThisTurn</code>.</p> * * @param dealtDamageList a {@link java.util.Map} object. */ public void setDealtDamageToThisTurn(Map<Card, Integer> dealtDamageList) { dealtDamageToThisTurn = dealtDamageList; } /** * <p>Getter for the field <code>dealtDamageToThisTurn</code>.</p> * * @return a {@link java.util.Map} object. */ public Map<Card, Integer> getDealtDamageToThisTurn() { return dealtDamageToThisTurn; } /** * <p>resetDealtDamageToThisTurn.</p> */ public void resetDealtDamageToThisTurn() { dealtDamageToThisTurn.clear(); } //how much damage is enough to kill the creature (for AI) /** * <p>getEnoughDamageToKill.</p> * * @param maxDamage a int. * @param source a {@link forge.Card} object. * @param isCombat a boolean. * @return a int. */ public int getEnoughDamageToKill(int maxDamage, Card source, boolean isCombat) { return getEnoughDamageToKill(maxDamage, source, isCombat, false); } /** * <p>getEnoughDamageToKill.</p> * * @param maxDamage a int. * @param source a {@link forge.Card} object. * @param isCombat a boolean. * @param noPrevention a boolean. * @return a int. */ public int getEnoughDamageToKill(int maxDamage, Card source, boolean isCombat, boolean noPrevention) { int killDamage = getKillDamage(); if (hasKeyword("Indestructible") || getShield() > 0) { if (!(source.hasKeyword("Wither") || source.hasKeyword("Infect"))) return maxDamage + 1; } else if (source.hasKeyword("Deathtouch")) { for (int i = 1; i <= maxDamage; i++) { if (noPrevention) { if (staticReplaceDamage(i, source, isCombat) > 0) return i; } else if (predictDamage(i, source, isCombat) > 0) return i; } } for (int i = 1; i <= maxDamage; i++) { if (noPrevention) { if (staticReplaceDamage(i, source, isCombat) >= killDamage) return i; } else { if (predictDamage(i, source, isCombat) >= killDamage) return i; } } return maxDamage + 1; } //the amount of damage needed to kill the creature (for AI) /** * <p>getKillDamage.</p> * * @return a int. */ public int getKillDamage() { int killDamage = getLethalDamage() + preventNextDamage; if (killDamage > preventNextDamage && hasStartOfKeyword("When CARDNAME is dealt damage, destroy it.")) killDamage = 1 + preventNextDamage; return killDamage; } //this is the minimal damage a trampling creature has to assign to a blocker /** * <p>getLethalDamage.</p> * * @return a int. */ public int getLethalDamage() { int lethalDamage = getNetDefense() - getDamage() - getTotalAssignedDamage(); return lethalDamage; } /** * <p>Setter for the field <code>damage</code>.</p> * * @param n a int. */ public void setDamage(int n) { //if (this.hasKeyword("Prevent all damage that would be dealt to CARDNAME.")) n = 0; damage = n; } /** * <p>Getter for the field <code>damage</code>.</p> * * @return a int. */ public int getDamage() { return damage; } /** * <p>addAssignedDamage.</p> * * @param damage a int. * @param sourceCard a {@link forge.Card} object. */ public void addAssignedDamage(int damage, Card sourceCard) { if (damage < 0) damage = 0; int assignedDamage = damage; Log.debug(this + " - was assigned " + assignedDamage + " damage, by " + sourceCard); if (!assignedDamageMap.containsKey(sourceCard)) assignedDamageMap.put(sourceCard, assignedDamage); else { assignedDamageMap.put(sourceCard, assignedDamageMap.get(sourceCard) + assignedDamage); } Log.debug("***"); /* if(sourceCards.size() > 1) System.out.println("(MULTIPLE blockers):"); System.out.println("Assigned " + damage + " damage to " + card); for (int i=0;i<sourceCards.size();i++){ System.out.println(sourceCards.get(i).getName() + " assigned damage to " + card.getName()); } System.out.println("***"); */ } /** * <p>clearAssignedDamage.</p> */ public void clearAssignedDamage() { assignedDamageMap.clear(); } /** * <p>getTotalAssignedDamage.</p> * * @return a int. */ public int getTotalAssignedDamage() { int total = 0; Collection<Integer> c = assignedDamageMap.values(); Iterator<Integer> itr = c.iterator(); while (itr.hasNext()) total += itr.next(); return total; } /** * <p>Getter for the field <code>assignedDamageMap</code>.</p> * * @return a {@link java.util.Map} object. */ public Map<Card, Integer> getAssignedDamageMap() { return assignedDamageMap; } /** * <p>addCombatDamage.</p> * * @param map a {@link java.util.Map} object. */ public void addCombatDamage(Map<Card, Integer> map) { CardList list = new CardList(); for (Entry<Card, Integer> entry : map.entrySet()) { Card source = entry.getKey(); list.add(source); int damageToAdd = entry.getValue(); damageToAdd = replaceDamage(damageToAdd, source, true); damageToAdd = preventDamage(damageToAdd, source, true); if (damageToAdd > 0 && isCreature()) { GameActionUtil.executeCombatDamageToCreatureEffects(source, this, damageToAdd); } map.put(source, damageToAdd); } if (AllZoneUtil.isCardInPlay(this)) { addDamage(map); } } //This function helps the AI calculate the actual amount of damage an effect would deal /** * <p>predictDamage.</p> * * @param damage a int. * @param possiblePrevention a int. * @param source a {@link forge.Card} object. * @param isCombat a boolean. * @return a int. */ public int predictDamage(final int damage, final int possiblePrevention, final Card source, final boolean isCombat) { int restDamage = damage; restDamage = staticReplaceDamage(restDamage, source, isCombat); restDamage = staticDamagePrevention(restDamage, possiblePrevention, source, isCombat); return restDamage; } //This function helps the AI calculate the actual amount of damage an effect would deal /** * <p>predictDamage.</p> * * @param damage a int. * @param source a {@link forge.Card} object. * @param isCombat a boolean. * @return a int. */ public int predictDamage(final int damage, final Card source, final boolean isCombat) { int restDamage = damage; restDamage = staticReplaceDamage(restDamage, source, isCombat); restDamage = staticDamagePrevention(restDamage, source, isCombat); return restDamage; } //This should be also usable by the AI to forecast an effect (so it must not change the game state) /** * <p>staticDamagePrevention.</p> * * @param damage a int. * @param possiblePrvenetion a int. * @param source a {@link forge.Card} object. * @param isCombat a boolean. * @return a int. */ public int staticDamagePrevention(final int damage, final int possiblePrvenetion, final Card source, final boolean isCombat) { if (AllZoneUtil.isCardInPlay("Leyline of Punishment")) return damage; int restDamage = damage - possiblePrvenetion; restDamage = staticDamagePrevention(restDamage, source, isCombat); return restDamage; } //This should be also usable by the AI to forecast an effect (so it must not change the game state) /** * <p>staticDamagePrevention.</p> * * @param damage a int. * @param source a {@link forge.Card} object. * @param isCombat a boolean. * @return a int. */ public int staticDamagePrevention(final int damage, final Card source, final boolean isCombat) { if (AllZoneUtil.isCardInPlay("Leyline of Punishment")) return damage; int restDamage = damage; Player player = getController(); if (CardFactoryUtil.hasProtectionFrom(source, this)) return 0; if (isCombat) { if (hasKeyword("Prevent all combat damage that would be dealt to and dealt by CARDNAME.")) return 0; if (hasKeyword("Prevent all combat damage that would be dealt to CARDNAME.")) return 0; if (source.hasKeyword("Prevent all combat damage that would be dealt to and dealt by CARDNAME.")) return 0; if (source.hasKeyword("Prevent all combat damage that would be dealt by CARDNAME.")) return 0; } if (hasKeyword("Prevent all damage that would be dealt to CARDNAME.")) return 0; if (hasKeyword("Prevent all damage that would be dealt to and dealt by CARDNAME.")) return 0; if (source.hasKeyword("Prevent all damage that would be dealt to and dealt by CARDNAME.")) return 0; if (source.hasKeyword("Prevent all damage that would be dealt by CARDNAME.")) return 0; if (hasStartOfKeyword("Absorb")) { int absorbed = this.getKeywordMagnitude("Absorb"); if (restDamage > absorbed) restDamage = restDamage - absorbed; else return 0; } if (hasStartOfKeyword("PreventAllDamageBy")) { String valid = getKeyword().get(getKeywordPosition("PreventAllDamageBy")); valid = valid.split(" ", 2)[1]; if (source.isValid(valid, this.getController(), this)) return 0; } //stPreventDamage CardList allp = AllZoneUtil.getCardsInPlay(); for (Card ca : allp) { if (ca.hasStartOfKeyword("stPreventDamage")) { //syntax stPreventDamage:[Who is protected(You/Player/ValidCards)]:[ValidSource]:[Amount/All] int KeywordPosition = ca.getKeywordPosition("stPreventDamage"); String parse = ca.getKeyword().get(KeywordPosition).toString(); String k[] = parse.split(":"); final String restrictions1[] = k[1].split(","); final String restrictions2[] = k[2].split(","); final Card card = ca; if (this.isValidCard(restrictions1, card.getController(), card) && source.isValidCard(restrictions2, card.getController(), card)) { if (k[3].equals("All")) return 0; restDamage = restDamage - Integer.valueOf(k[3]); } } } //stPreventDamage // specific Cards if (isCreature()) { //and not a planeswalker if (getName().equals("Swans of Bryn Argoll")) return 0; if ((source.isCreature() && AllZoneUtil.isCardInPlay("Well-Laid Plans") && source.sharesColorWith(this))) return 0; if ((!isCombat && AllZoneUtil.isCardInPlay("Mark of Asylum", player))) return 0; if (getName().equals("Callous Giant") && restDamage <= 3) return 0; } //Creature end if (restDamage > 0) return restDamage; else return 0; } /** * <p>preventDamage.</p> * * @param damage a int. * @param source a {@link forge.Card} object. * @param isCombat a boolean. * @return a int. */ public int preventDamage(final int damage, Card source, boolean isCombat) { if (AllZoneUtil.isCardInPlay("Leyline of Punishment")) return damage; int restDamage = damage; if (getName().equals("Swans of Bryn Argoll")) { source.getController().drawCards(restDamage); return 0; } restDamage = staticDamagePrevention(restDamage, source, isCombat); if (restDamage == 0) return 0; if (this.hasKeyword("If damage would be dealt to CARDNAME, prevent that damage. Remove a +1/+1 counter from CARDNAME.")) { restDamage = 0; this.subtractCounter(Counters.P1P1, 1); } if (restDamage >= preventNextDamage) { restDamage = restDamage - preventNextDamage; preventNextDamage = 0; } else { restDamage = 0; preventNextDamage = preventNextDamage - restDamage; } if (getName().equals("Phyrexian Hydra")) { addCounter(Counters.M1M1, restDamage); return 0; } return restDamage; } //This should be also usable by the AI to forecast an effect (so it must not change the game state) /** * <p>staticReplaceDamage.</p> * * @param damage a int. * @param source a {@link forge.Card} object. * @param isCombat a boolean. * @return a int. */ public int staticReplaceDamage(final int damage, Card source, boolean isCombat) { int restDamage = damage; if (AllZoneUtil.isCardInPlay("Sulfuric Vapors") && source.isSpell() && source.isRed()) { int amount = AllZoneUtil.getCardsInPlay("Sulfuric Vapors").size(); for (int i = 0; i < amount; i++) restDamage += 1; } if (AllZoneUtil.isCardInPlay("Furnace of Rath") && isCreature()) { int amount = AllZoneUtil.getCardsInPlay("Furnace of Rath").size(); for (int i = 0; i < amount; i++) restDamage += restDamage; } if (AllZoneUtil.isCardInPlay("Gratuitous Violence", source.getController()) && source.isCreature() && isCreature()) { int amount = AllZoneUtil.getPlayerCardsInPlay(source.getController(), "Gratuitous Violence").size(); for (int i = 0; i < amount; i++) restDamage += restDamage; } if (AllZoneUtil.isCardInPlay("Fire Servant", source.getController()) && source.isRed() && (source.isInstant() || source.isSorcery())) { int amount = AllZoneUtil.getPlayerCardsInPlay(source.getController(), "Fire Servant").size(); for (int i = 0; i < amount; i++) restDamage += restDamage; } if (AllZoneUtil.isCardInPlay("Benevolent Unicorn") && source.isSpell() && isCreature()) { int amount = AllZoneUtil.getCardsInPlay("Benevolent Unicorn").size(); for (int i = 0; i < amount; i++) if (restDamage > 0) restDamage -= 1; } if (AllZoneUtil.isCardInPlay("Lashknife Barrier", getController()) && isCreature()) { int amount = AllZoneUtil.getPlayerCardsInPlay(getController(), "Lashknife Barrier").size(); for (int i = 0; i < amount; i++) if (restDamage > 0) restDamage -= 1; } if (AllZoneUtil.isCardInPlay("Divine Presence") && isCreature() && restDamage > 3) { restDamage = 3; } if (getName().equals("Phytohydra")) { return 0; } return restDamage; } /** * <p>replaceDamage.</p> * * @param damage a int. * @param source a {@link forge.Card} object. * @param isCombat a boolean. * @return a int. */ public int replaceDamage(final int damage, Card source, boolean isCombat) { int restDamage = damage; CardList auras = new CardList(getEnchantedBy().toArray()); if (getName().equals("Phytohydra")) { addCounter(Counters.P1P1, restDamage); return 0; } if (auras.containsName("Treacherous Link")) { getController().addDamage(restDamage, source); return 0; } restDamage = staticReplaceDamage(restDamage, source, isCombat); if (getName().equals("Lichenthrope")) { addCounter(Counters.M1M1, restDamage); return 0; } return restDamage; } /** * <p>addDamage.</p> * * @param sourcesMap a {@link java.util.Map} object. */ public void addDamage(Map<Card, Integer> sourcesMap) { for (Entry<Card, Integer> entry : sourcesMap.entrySet()) { addDamageAfterPrevention(entry.getValue(), entry.getKey(), true); // damage prevention is already checked! } } //This is for noncombat damage /** * <p>addDamage.</p> * * @param damageIn a int. * @param source a {@link forge.Card} object. */ public void addDamage(final int damageIn, final Card source) { int damageToAdd = damageIn; damageToAdd = replaceDamage(damageToAdd, source, false); damageToAdd = preventDamage(damageToAdd, source, false); addDamageAfterPrevention(damageToAdd, source, false); } /** * <p>addDamageWithoutPrevention.</p> * * @param damageIn a int. * @param source a {@link forge.Card} object. */ public void addDamageWithoutPrevention(final int damageIn, final Card source) { int damageToAdd = damageIn; damageToAdd = replaceDamage(damageToAdd, source, false); addDamageAfterPrevention(damageToAdd, source, false); } //This function handles damage after replacement and prevention effects are applied /** * <p>addDamageAfterPrevention.</p> * * @param damageIn a int. * @param source a {@link forge.Card} object. * @param isCombat a boolean. */ public void addDamageAfterPrevention(final int damageIn, final Card source, final boolean isCombat) { int damageToAdd = damageIn; boolean wither = false; if (damageToAdd == 0) return; //Rule 119.8 System.out.println("Adding " + damageToAdd + " damage to " + getName()); Log.debug("Adding " + damageToAdd + " damage to " + getName()); addReceivedDamageFromThisTurn(source, damageToAdd); source.addDealtDamageToThisTurn(this, damageToAdd); GameActionUtil.executeDamageDealingEffects(source, damageToAdd); //Run triggers Map<String, Object> runParams = new TreeMap<String, Object>(); runParams.put("DamageSource", source); runParams.put("DamageTarget", this); runParams.put("DamageAmount", damageToAdd); runParams.put("IsCombatDamage", isCombat); AllZone.getTriggerHandler().runTrigger("DamageDone", runParams); if (this.isPlaneswalker()) { this.subtractCounter(Counters.LOYALTY, damageToAdd); return; } if ((source.hasKeyword("Wither") || source.hasKeyword("Infect"))) wither = true; GameActionUtil.executeDamageToCreatureEffects(source, this, damageToAdd); if (AllZoneUtil.isCardInPlay(this) && wither) addCounter(Counters.M1M1, damageToAdd); if (AllZoneUtil.isCardInPlay(this) && !wither) damage += damageToAdd; } private ArrayList<SetInfo> Sets = new ArrayList<SetInfo>(); private String curSetCode = ""; /** * <p>addSet.</p> * * @param sInfo a {@link forge.SetInfo} object. */ public void addSet(SetInfo sInfo) { Sets.add(sInfo); } /** * <p>getSets.</p> * * @return a {@link java.util.ArrayList} object. */ public ArrayList<SetInfo> getSets() { return Sets; } /** * <p>setSets.</p> * * @param siList a {@link java.util.ArrayList} object. */ public void setSets(ArrayList<SetInfo> siList) { Sets = siList; } /** * <p>Setter for the field <code>curSetCode</code>.</p> * * @param setCode a {@link java.lang.String} object. */ public void setCurSetCode(String setCode) { curSetCode = setCode; } /** * <p>Getter for the field <code>curSetCode</code>.</p> * * @return a {@link java.lang.String} object. */ public String getCurSetCode() { return curSetCode; } /** * <p>setRandomSetCode.</p> */ public void setRandomSetCode() { if (Sets.size() < 1) return; Random r = MyRandom.random; SetInfo si = Sets.get(r.nextInt(Sets.size())); curSetCode = si.Code; } /** * <p>getSetImageName.</p> * * @param setCode a {@link java.lang.String} object. * @return a {@link java.lang.String} object. */ public String getSetImageName(String setCode) { return "/" + setCode + "/" + getImageName(); } /** * <p>getCurSetImage.</p> * * @return a {@link java.lang.String} object. */ public String getCurSetImage() { return getSetImageName(curSetCode); } /** * <p>getCurSetRarity.</p> * * @return a {@link java.lang.String} object. */ public String getCurSetRarity() { for (int i = 0; i < Sets.size(); i++) if (Sets.get(i).Code.equals(curSetCode)) return Sets.get(i).Rarity; return ""; } /** * <p>getCurSetURL.</p> * * @return a {@link java.lang.String} object. */ public String getCurSetURL() { for (int i = 0; i < Sets.size(); i++) if (Sets.get(i).Code.equals(curSetCode)) return Sets.get(i).URL; return ""; } /** * <p>getMostRecentSet.</p> * * @return a {@link java.lang.String} object. */ public String getMostRecentSet() { return SetInfoUtil.getMostRecentSet(Sets); } private String ImageFilename = ""; /** * <p>setImageFilename.</p> * * @param iFN a {@link java.lang.String} object. */ public void setImageFilename(String iFN) { ImageFilename = iFN; } /** * <p>getImageFilename.</p> * * @return a {@link java.lang.String} object. */ public String getImageFilename() { return ImageFilename; } /** * <p>Setter for the field <code>evoked</code>.</p> * * @param evoked a boolean. */ public void setEvoked(boolean evoked) { this.evoked = evoked; } /** * <p>isEvoked.</p> * * @return a boolean. */ public boolean isEvoked() { return evoked; } public void setTimestamp(long t) { timestamp = t; } public long getTimestamp() { return timestamp; } //private int foil = 0; public int getFoil() { if (SVars.containsKey("Foil")) { return Integer.parseInt(SVars.get("Foil")); } return 0; } public void setFoil(int f) { SVars.put("Foil", Integer.toString(f)); } }//end Card class