Java tutorial
/* * 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.replacement; import forge.card.MagicColor; import forge.game.Game; import forge.game.GameLogEntryType; import forge.game.ability.AbilityFactory; import forge.game.ability.AbilityUtils; import forge.game.card.Card; import forge.game.player.Player; import forge.game.spellability.SpellAbility; import forge.game.zone.ZoneType; import forge.util.FileSection; import forge.util.Visitor; import org.apache.commons.lang3.StringUtils; import java.util.*; public class ReplacementHandler { private final Game game; /** * ReplacementHandler. * @param gameState */ public ReplacementHandler(Game gameState) { game = gameState; } //private final List<ReplacementEffect> tmpEffects = new ArrayList<ReplacementEffect>(); public ReplacementResult run(final HashMap<String, Object> runParams) { final Object affected = runParams.get("Affected"); Player decider = null; // Figure out who decides which of multiple replacements to apply // as well as whether or not to apply optional replacements. if (affected instanceof Player) { decider = (Player) affected; } else { decider = ((Card) affected).getController(); } final Game game = decider.getGame(); if (runParams.get("Event").equals("Moved")) { ReplacementResult res = run(runParams, ReplacementLayer.Control, decider, game); if (res != ReplacementResult.NotReplaced) { return res; } res = run(runParams, ReplacementLayer.Copy, decider, game); if (res != ReplacementResult.NotReplaced) { return res; } res = run(runParams, ReplacementLayer.Other, decider, game); if (res != ReplacementResult.NotReplaced) { return res; } res = run(runParams, ReplacementLayer.None, decider, game); if (res != ReplacementResult.NotReplaced) { return res; } } else { ReplacementResult res = run(runParams, ReplacementLayer.None, decider, game); if (res != ReplacementResult.NotReplaced) { return res; } } return ReplacementResult.NotReplaced; } /** * * Runs any applicable replacement effects. * * @param runParams * the run params,same as for triggers. * @return true if the event was replaced. */ public ReplacementResult run(final HashMap<String, Object> runParams, final ReplacementLayer layer, final Player decider, final Game game) { final List<ReplacementEffect> possibleReplacers = new ArrayList<ReplacementEffect>(); // Round up Non-static replacement effects ("Until EOT," or // "The next time you would..." etc) /*for (final ReplacementEffect replacementEffect : this.tmpEffects) { if (!replacementEffect.hasRun() && replacementEffect.canReplace(runParams) && replacementEffect.getLayer() == layer) { possibleReplacers.add(replacementEffect); } }*/ // Round up Static replacement effects for (final Player p : game.getPlayers()) { for (final Card crd : p.getAllCards()) { for (final ReplacementEffect replacementEffect : crd.getReplacementEffects()) { if (!replacementEffect.hasRun() && replacementEffect.getLayer() == layer && replacementEffect.requirementsCheck(game) && replacementEffect.canReplace(runParams) && !possibleReplacers.contains(replacementEffect) && replacementEffect.zonesCheck(game.getZoneOf(crd))) { possibleReplacers.add(replacementEffect); } } } } if (possibleReplacers.isEmpty()) { return ReplacementResult.NotReplaced; } ReplacementEffect chosenRE = decider.getController().chooseSingleReplacementEffect( "Choose a replacement effect to apply first.", possibleReplacers, runParams); possibleReplacers.remove(chosenRE); chosenRE.setHasRun(true); ReplacementResult res = this.executeReplacement(runParams, chosenRE, decider, game); if (res == ReplacementResult.NotReplaced) { if (!possibleReplacers.isEmpty()) { res = run(runParams); } chosenRE.setHasRun(false); return res; } chosenRE.setHasRun(false); String message = chosenRE.toString(); if (!StringUtils.isEmpty(message)) if (chosenRE.getHostCard() != null) { message = message.replaceAll("CARDNAME", chosenRE.getHostCard().getName()); } game.getGameLog().add(GameLogEntryType.EFFECT_REPLACED, message); return res; } /** * * Runs a single replacement effect. * * @param replacementEffect * the replacement effect to run */ private ReplacementResult executeReplacement(final Map<String, Object> runParams, final ReplacementEffect replacementEffect, final Player decider, final Game game) { final Map<String, String> mapParams = replacementEffect.getMapParams(); SpellAbility effectSA = null; if (mapParams.containsKey("ReplaceWith")) { final String effectSVar = mapParams.get("ReplaceWith"); final String effectAbString = replacementEffect.getHostCard().getSVar(effectSVar); // TODO: the source of replacement effect should be the source of the original effect effectSA = AbilityFactory.getAbility(effectAbString, replacementEffect.getHostCard()); effectSA.setTrigger(true); SpellAbility tailend = effectSA; do { replacementEffect.setReplacingObjects(runParams, tailend); tailend = tailend.getSubAbility(); } while (tailend != null); } else if (replacementEffect.getOverridingAbility() != null) { effectSA = replacementEffect.getOverridingAbility(); SpellAbility tailend = effectSA; do { replacementEffect.setReplacingObjects(runParams, tailend); tailend = tailend.getSubAbility(); } while (tailend != null); } if (effectSA != null && replacementEffect.isIntrinsic()) { effectSA.setIntrinsic(true); effectSA.changeText(); effectSA.setReplacementAbility(true); } // Decider gets to choose whether or not to apply the replacement. if (replacementEffect.getMapParams().containsKey("Optional")) { Player optDecider = decider; if (mapParams.containsKey("OptionalDecider") && (effectSA != null)) { effectSA.setActivatingPlayer(replacementEffect.getHostCard().getController()); optDecider = AbilityUtils.getDefinedPlayers(replacementEffect.getHostCard(), mapParams.get("OptionalDecider"), effectSA).get(0); } Card cardForUi = replacementEffect.getHostCard().getCardForUi(); String effectDesc = replacementEffect.toString().replace("CARDNAME", cardForUi.getName()); final String question = replacementEffect instanceof ReplaceDiscard ? String.format("Apply replacement effect of %s to %s?\r\n(%s)", cardForUi, runParams.get("Card").toString(), effectDesc) : String.format("Apply replacement effect of %s?\r\n(%s)", cardForUi, effectDesc); boolean confirmed = optDecider.getController().confirmReplacementEffect(replacementEffect, effectSA, question); if (!confirmed) { return ReplacementResult.NotReplaced; } } if (mapParams.containsKey("Prevent")) { if (mapParams.get("Prevent").equals("True")) { return ReplacementResult.Prevented; // Nothing should replace the event. } } Player player = replacementEffect.getHostCard().getController(); if (mapParams.containsKey("ManaReplacement")) { final SpellAbility manaAb = (SpellAbility) runParams.get("AbilityMana"); final Player player1 = (Player) runParams.get("Player"); final String rep = (String) runParams.get("Mana"); // Replaced mana type final Card repHost = replacementEffect.getHostCard(); String repType = repHost.getSVar(mapParams.get("ManaReplacement")); if (repType.contains("Chosen") && repHost.hasChosenColor()) { repType = repType.replace("Chosen", MagicColor.toShortString(repHost.getChosenColor())); } manaAb.getManaPart().setManaReplaceType(repType); manaAb.getManaPart().produceMana(rep, player1, manaAb); } else { player.getController().playSpellAbilityNoStack(effectSA, true); } return ReplacementResult.Replaced; } /** * * Creates an instance of the proper replacement effect object based on raw * script. * * @param repParse * A raw line of script * @param host * The cards that hosts the replacement effect. * @return A finished instance */ public static ReplacementEffect parseReplacement(final String repParse, final Card host, final boolean intrinsic) { final Map<String, String> mapParams = FileSection.parseToMap(repParse, "$", "|"); return ReplacementHandler.parseReplacement(mapParams, host, intrinsic); } /** * * Creates an instance of the proper replacement effect object based on a * parsed script. * * @param mapParams * The parsed script * @param host * The card that hosts the replacement effect * @return The finished instance */ private static ReplacementEffect parseReplacement(final Map<String, String> mapParams, final Card host, final boolean intrinsic) { final ReplacementType rt = ReplacementType.smartValueOf(mapParams.get("Event")); ReplacementEffect ret = rt.createReplacement(mapParams, host, intrinsic); String activeZones = mapParams.get("ActiveZones"); if (null != activeZones) { ret.setActiveZone(EnumSet.copyOf(ZoneType.listValueOf(activeZones))); } return ret; } public void cleanUpTemporaryReplacements() { game.forEachCardInGame(new Visitor<Card>() { @Override public void visit(Card c) { for (int i = 0; i < c.getReplacementEffects().size(); i++) { ReplacementEffect rep = c.getReplacementEffects().get(i); if (rep.isTemporary()) { c.removeReplacementEffect(rep); i--; } } } }); game.forEachCardInGame(new Visitor<Card>() { @Override public void visit(Card c) { for (int i = 0; i < c.getReplacementEffects().size(); i++) { c.getReplacementEffects().get(i).setTemporarilySuppressed(false); } } }); } }