forge.game.spellability.AbilityManaPart.java Source code

Java tutorial

Introduction

Here is the source code for forge.game.spellability.AbilityManaPart.java

Source

/*
 * Forge: Play Magic: the Gathering.
 * Copyright (C) 2011  Forge Team
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package forge.game.spellability;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;

import forge.card.ColorSet;
import forge.card.MagicColor;
import forge.game.card.Card;
import forge.game.mana.Mana;
import forge.game.mana.ManaPool;
import forge.game.player.Player;
import forge.game.replacement.ReplacementEffect;
import forge.game.replacement.ReplacementHandler;
import forge.game.replacement.ReplacementLayer;
import forge.game.replacement.ReplacementResult;
import forge.game.trigger.TriggerType;

/**
 * <p>
 * Abstract AbilityMana class.
 * </p>
 * 
 * @author Forge
 * @version $Id: AbilityManaPart.java 29500 2015-05-30 16:37:15Z Agetian $
 */
public class AbilityManaPart implements java.io.Serializable {
    /** Constant <code>serialVersionUID=-6816356991224950520L</code>. */
    private static final long serialVersionUID = -6816356991224950520L;

    private final String origProduced;
    private String lastExpressChoice = "";
    private final String manaRestrictions;
    private final String cannotCounterSpell;
    private final String addsKeywords;
    private final String addsKeyowrdsType;
    private final String addsKeywordsUntil;
    private final String addsCounters;
    private final boolean persistentMana;
    private String manaReplaceType;

    private transient List<Mana> lastManaProduced = new ArrayList<Mana>();

    private final transient Card sourceCard;

    // Spells paid with this mana spell can't be countered.

    /**
     * <p>
     * Constructor for AbilityMana.
     * </p>
     * 
     * @param sourceCard
     *            a {@link forge.game.card.Card} object.
     * @param parse
     *            a {@link java.lang.String} object.
     * @param produced
     *            a {@link java.lang.String} object.
     * @param num
     *            a int.
     */
    public AbilityManaPart(final Card sourceCard, final Map<String, String> params) {
        this.sourceCard = sourceCard;

        origProduced = params.containsKey("Produced") ? params.get("Produced") : "1";
        this.manaRestrictions = params.containsKey("RestrictValid") ? params.get("RestrictValid") : "";
        this.cannotCounterSpell = params.get("AddsNoCounter");
        this.addsKeywords = params.get("AddsKeywords");
        this.addsKeyowrdsType = params.get("AddsKeywordsType");
        this.addsKeywordsUntil = params.get("AddsKeywordsUntil");
        this.addsCounters = params.get("AddsCounters");
        this.persistentMana = (null == params.get("PersistentMana")) ? false
                : "True".equalsIgnoreCase(params.get("PersistentMana"));
        this.manaReplaceType = params.containsKey("ManaReplaceType") ? params.get("ManaReplaceType") : "";
    }

    /**
     * <p>
     * produceMana.
     * </p>
     * @param ability
     */
    public final void produceMana(SpellAbility sa) {
        this.produceMana(this.getOrigProduced(), this.getSourceCard().getController(), sa);
    }

    /**
     * <p>
     * produceMana.
     * </p>
     * 
     * @param produced
     *            a {@link java.lang.String} object.
     * @param player
     *            a {@link forge.game.player.Player} object.
     * @param sa
     */
    public final void produceMana(final String produced, final Player player, SpellAbility sa) {
        final Card source = this.getSourceCard();
        final ManaPool manaPool = player.getManaPool();
        String afterReplace = applyManaReplacement(sa, produced);
        final HashMap<String, Object> repParams = new HashMap<String, Object>();
        repParams.put("Event", "ProduceMana");
        repParams.put("Mana", afterReplace);
        repParams.put("Affected", source);
        repParams.put("Player", player);
        repParams.put("AbilityMana", sa);
        if (player.getGame().getReplacementHandler().run(repParams) != ReplacementResult.NotReplaced) {
            return;
        }
        ColorSet CID = null;

        if (player.getGame().getRules().hasCommander()) {
            CID = player.getCommander().getRules().getColorIdentity();
        }
        //clear lastProduced
        this.lastManaProduced.clear();

        // loop over mana produced string
        for (final String c : afterReplace.split(" ")) {
            if (StringUtils.isNumeric(c)) {
                for (int i = Integer.parseInt(c); i > 0; i--) {
                    this.lastManaProduced.add(new Mana(MagicColor.COLORLESS, source, this));
                }
            } else {
                byte attemptedMana = MagicColor.fromName(c);
                if (CID != null) {
                    if (!CID.hasAnyColor(attemptedMana)) {
                        attemptedMana = MagicColor.COLORLESS;
                    }
                }

                this.lastManaProduced.add(new Mana(attemptedMana, source, this));
            }
        }

        // add the mana produced to the mana pool
        manaPool.add(this.lastManaProduced);

        // Run triggers
        final HashMap<String, Object> runParams = new HashMap<String, Object>();

        runParams.put("Card", source);
        runParams.put("Player", player);
        runParams.put("AbilityMana", sa);
        runParams.put("Produced", afterReplace);
        player.getGame().getTriggerHandler().runTrigger(TriggerType.TapsForMana, runParams, false);
        // Clear Mana replacement
        this.manaReplaceType = "";
    } // end produceMana(String)

    /**
     * <p>
     * cannotCounterPaidWith.
     * </p>
     * @param saBeingPaid
     * 
     * @return a {@link java.lang.String} object.
     */
    public boolean cannotCounterPaidWith(SpellAbility saBeingPaid) {
        if (null == cannotCounterSpell)
            return false;
        if ("True".equalsIgnoreCase(cannotCounterSpell))
            return true;

        Card source = saBeingPaid.getHostCard();
        if (source == null)
            return false;
        return source.isValid(cannotCounterSpell, sourceCard.getController(), sourceCard);
    }

    /**
     * <p>
     * addKeywords.
     * </p>
     * @param saBeingPaid
     * 
     * @return a {@link java.lang.String} object.
     */
    public boolean addKeywords(SpellAbility saBeingPaid) {
        return this.addsKeywords != null;
    }

    public String getAddsKeyowrdsType() {
        return addsKeyowrdsType;
    }

    public String getAddsKeywordsUntil() {
        return addsKeywordsUntil;
    }

    /**
     * <p>
     * getKeywords.
     * </p>
     * @param saBeingPaid
     * 
     * @return a {@link java.lang.String} object.
     */
    public String getKeywords() {
        return this.addsKeywords;
    }

    /**
     * <p>
     * addsCounters.
     * </p>
     * @param saBeingPaid
     * 
     * @return a {@link java.lang.String} object.
     */
    public boolean addsCounters(SpellAbility saBeingPaid) {
        return this.addsCounters != null;
    }

    /**
     * createETBCounters
     */
    public void createETBCounters(Card c) {
        String[] parse = this.addsCounters.split("_");
        // Convert random SVars if there are other cards with this effect
        if (c.isValid(parse[0], c.getController(), c)) {
            String abStr = "DB$ PutCounter | Defined$ Self | CounterType$ " + parse[1]
                    + " | ETB$ True | CounterNum$ " + parse[2] + " | SubAbility$ ManaDBETBCounters";
            String dbStr = "DB$ ChangeZone | Hidden$ True | Origin$ All | Destination$ Battlefield"
                    + " | Defined$ ReplacedCard";
            try {
                Integer.parseInt(parse[2]);
            } catch (NumberFormatException ignored) {
                dbStr += " | References$ " + parse[2];
                c.setSVar(parse[2], sourceCard.getSVar(parse[2]));
            }
            c.setSVar("ManaETBCounters", abStr);
            c.setSVar("ManaDBETBCounters", dbStr);

            String repeffstr = "Event$ Moved | ValidCard$ Card.Self | Destination$ Battlefield "
                    + "| ReplaceWith$ ManaETBCounters | Secondary$ True | Description$ CARDNAME"
                    + " enters the battlefield with " + parse[1] + " counters.";

            ReplacementEffect re = ReplacementHandler.parseReplacement(repeffstr, c, false);
            re.setLayer(ReplacementLayer.Other);

            c.addReplacementEffect(re);
        }
    }

    /**
     * <p>
     * getManaRestrictions.
     * </p>
     * 
     * @return a {@link java.lang.String} object.
     */
    public String getManaRestrictions() {
        return this.manaRestrictions;
    }

    /**
     * <p>
     * meetsManaRestrictions.
     * </p>
     * 
     * @param sa
     *            a {@link forge.game.spellability.SpellAbility} object.
     * @return a boolean.
     */
    public boolean meetsManaRestrictions(final SpellAbility sa) {
        // No restrictions
        if (this.manaRestrictions.isEmpty()) {
            return true;
        }

        // Loop over restrictions
        for (String restriction : this.manaRestrictions.split(",")) {
            if (restriction.equals("nonSpell")) {
                return !sa.isSpell();
            }

            if (restriction.equals("CumulativeUpkeep")) {
                if (sa.isCumulativeupkeep()) {
                    return true;
                } else {
                    continue;
                }
            }

            if (restriction.startsWith("CostContainsX")) {
                if (sa.isXCost()) {
                    return true;
                }
                continue;
            }
            if (restriction.equals("MorphOrManifest")) {
                if ((sa.isSpell() && sa.getHostCard().isCreature() && ((Spell) sa).isCastFaceDown())
                        || sa.isManifestUp() || sa.isMorphUp()) {
                    return true;
                } else {
                    continue;
                }
            }

            if (sa.isAbility()) {
                if (restriction.startsWith("Activated")) {
                    restriction = restriction.replace("Activated", "Card");
                } else {
                    continue;
                }
            }

            if (sa.getHostCard() != null) {
                if (sa.getHostCard().isValid(restriction, this.getSourceCard().getController(),
                        this.getSourceCard())) {
                    return true;
                }
            }

        }

        return false;
    }

    /**
     * <p>
     * mana.
     * </p>
     * 
     * @return a {@link java.lang.String} object.
     */
    public final String mana() {
        if (this.getOrigProduced().contains("Chosen")) {
            if (this.getSourceCard() != null && this.getSourceCard().hasChosenColor()) {
                return MagicColor.toShortString(this.getSourceCard().getChosenColor());
            }
        }
        return this.getOrigProduced();
    }

    /**
     * <p>
     * setAnyChoice.
     * </p>
     *
     * @param s a {@link java.lang.String} object.
     */
    public void setExpressChoice(String s) {
        this.lastExpressChoice = s;
    }

    public void setExpressChoice(ColorSet cs) {
        StringBuilder sb = new StringBuilder();
        if (cs.hasBlack())
            sb.append("B ");
        if (cs.hasBlue())
            sb.append("U ");
        if (cs.hasWhite())
            sb.append("W ");
        if (cs.hasRed())
            sb.append("R ");
        if (cs.hasGreen())
            sb.append("G ");
        this.lastExpressChoice = sb.toString().trim();
    }

    /**
     * <p>
     * Getter for the field <code>lastAnyChoice</code>.
     * </p>
     *
     * @return a {@link java.lang.String} object.
     */
    public String getExpressChoice() {
        return this.lastExpressChoice;
    }

    /**
     * <p>
     * clearExpressChoice.
     * </p>
     *
     */
    public void clearExpressChoice() {
        this.lastExpressChoice = "";
    }

    /**
     * <p>
     * Getter for the field <code>lastProduced</code>.
     * </p>
     *
     * @return a {@link java.lang.String} object.
     */
    public List<Mana> getLastManaProduced() {
        return this.lastManaProduced;
    }

    /**
     * <p>
     * isSnow.
     * </p>
     * 
     * @return a boolean.
     */
    public final boolean isSnow() {
        return this.getSourceCard().isSnow();
    }

    /**
     * <p>
     * isAnyMana.
     * </p>
     *
     * @return a boolean.
     */
    public boolean isAnyMana() {
        return this.getOrigProduced().contains("Any");
    }

    /**
     * <p>
     * isComboMana.
     * </p>
     *
     * @return a boolean.
     */
    public boolean isComboMana() {
        return this.getOrigProduced().contains("Combo");
    }

    /**
     * <p>
     * isSpecialMana.
     * </p>
     *
     * @return a boolean.
     */
    public boolean isSpecialMana() {
        return this.getOrigProduced().contains("Special");
    }

    /**
     * <p>
     * canProduce.
     * </p>
     * 
     * @param s
     *            a {@link java.lang.String} object.
     * @return a boolean.
     */
    public final boolean canProduce(final String s) {
        return canProduce(s, null);
    }

    /**
     * <p>
     * canProduce.
     * </p>
     * 
     * @param s
     *            a {@link java.lang.String} object.
     * @return a boolean.
     */
    public final boolean canProduce(final String s, final SpellAbility sa) {
        if (isAnyMana()) {
            return true;
        }

        if (this.getOrigProduced().contains("Chosen") && sourceCard != null) {
            if (this.getSourceCard().hasChosenColor()
                    && MagicColor.toShortString(this.getSourceCard().getChosenColor()).contains(s)) {
                return true;
            }
        }
        if (sa != null) {
            return applyManaReplacement(sa, this.getOrigProduced()).contains(s);
        }
        return this.getOrigProduced().contains(s);
    }

    /**
     * <p>
     * isBasic.
     * </p>
     * 
     * @return a boolean.
     */
    public final boolean isBasic() {
        if (this.getOrigProduced().length() != 1 && !this.getOrigProduced().contains("Any")
                && !this.getOrigProduced().contains("Chosen")) {
            return false;
        }

        return true;
    }

    /** {@inheritDoc} */
    @Override
    public final boolean equals(final Object o) {
        // Mana abilities with same Descriptions are "equal"
        if ((o == null) || !(o instanceof AbilityManaPart)) {
            return false;
        }

        final AbilityManaPart abm = (AbilityManaPart) o;

        return sourceCard.equals(abm.sourceCard) && origProduced.equals(abm.getOrigProduced());
    }

    /** {@inheritDoc} */
    @Override
    public int hashCode() {
        return (41 * (41 + this.getSourceCard().hashCode()));
    }

    /**
     * @return the origProduced
     */
    public String getOrigProduced() {
        return origProduced;
    }

    /**
     * @return the color available in combination mana
     */
    public String getComboColors() {
        String retVal = "";
        if (this.getOrigProduced().contains("Combo")) {
            retVal = this.getOrigProduced().replace("Combo ", "");
            if (retVal.contains("Any")) {
                retVal = "W U B R G";
            }
            if (retVal.contains("ColorIdentity")) {
                retVal = "";
                Card cmdr = this.getSourceCard().getController().getCommander();
                if (cmdr == null) {
                    return retVal;
                }
                ColorSet CID = cmdr.getRules().getColorIdentity();
                if (CID.hasWhite()) {
                    retVal += "W ";
                }
                if (CID.hasBlue()) {
                    retVal += "U ";
                }
                if (CID.hasBlack()) {
                    retVal += "B ";
                }
                if (CID.hasRed()) {
                    retVal += "R ";
                }
                if (CID.hasGreen()) {
                    retVal += "G ";
                }
                retVal = retVal.substring(0, retVal.length() - 1);
            }
        }
        return retVal;
    }

    public Card getSourceCard() {
        return sourceCard;
    }

    /**
     * <p>
     * isPersistentMana.
     * </p>
     *
     * @return a boolean.
     */
    public boolean isPersistentMana() {
        return this.persistentMana;
    }

    /**
     * @return the manaReplaceType
     */
    public String getManaReplaceType() {
        return manaReplaceType;
    }

    /**
     * setManaReplaceType.
     */
    public void setManaReplaceType(final String type) {
        this.manaReplaceType = type;
    }

    /**
     * <p>
     * applyManaReplacement.
     * </p>
     * @return a String
     */
    public static String applyManaReplacement(final SpellAbility sa, final String original) {
        final HashMap<String, String> repMap = new HashMap<String, String>();
        final Player act = sa != null ? sa.getActivatingPlayer() : null;
        final String manaReplace = sa != null ? sa.getManaPart().getManaReplaceType() : "";
        if (manaReplace.isEmpty()) {
            if (act != null && act.getLandsPlayedThisTurn() > 0 && sa.hasParam("ReplaceIfLandPlayed")) {
                return sa.getParam("ReplaceIfLandPlayed");
            }
            return original;
        }
        if (manaReplace.startsWith("Any")) {
            // Replace any type and amount
            String replaced = manaReplace.split("->")[1];
            if (replaced.equals("Any")) {
                byte rs = MagicColor.GREEN;
                if (act != null) {
                    rs = act.getController().chooseColor("Choose a color", sa, ColorSet.ALL_COLORS);
                }
                replaced = MagicColor.toShortString(rs);
            }
            return replaced;
        }
        final Pattern splitter = Pattern.compile("->");
        // Replace any type
        for (String part : manaReplace.split(" & ")) {
            final String[] v = splitter.split(part, 2);
            if (v[0].equals("Colorless")) {
                repMap.put("[0-9][0-9]?", v.length > 1 ? v[1].trim() : "");
            } else {
                repMap.put(v[0], v.length > 1 ? v[1].trim() : "");
            }
        }
        // Handle different replacement simultaneously
        Pattern pattern = Pattern.compile(StringUtils.join(repMap.keySet().iterator(), "|"));
        Matcher m = pattern.matcher(original);
        StringBuffer sb = new StringBuffer();
        while (m.find()) {
            if (m.group().matches("[0-9][0-9]?")) {
                final String rep = StringUtils.repeat(repMap.get("[0-9][0-9]?") + " ", Integer.parseInt(m.group()))
                        .trim();
                m.appendReplacement(sb, rep);
            } else {
                m.appendReplacement(sb, repMap.get(m.group()));
            }
        }
        m.appendTail(sb);
        String replaced = sb.toString();
        while (replaced.contains("Any")) {
            byte rs = MagicColor.GREEN;
            if (act != null) {
                rs = act.getController().chooseColor("Choose a color", sa, ColorSet.ALL_COLORS);
            }
            replaced = replaced.replaceFirst("Any", MagicColor.toShortString(rs));
        }
        return replaced;
    }

} // end class AbilityMana