@Override
  public PaymentDecision visit(CostExileFromStack cost) {

    Integer c = cost.convertAmount();
    if (c == null) {
      final String sVar = ability.getSVar(cost.getAmount());
      // Generalize cost
      if (sVar.equals("XChoice")) {
        return null;
      }
      c = AbilityUtils.calculateAmount(source, cost.getAmount(), ability);
    }
    List<SpellAbility> chosen = new ArrayList<SpellAbility>();
    for (SpellAbilityStackInstance si : source.getGame().getStack()) {
      SpellAbility sp = si.getSpellAbility().getRootAbility();
      if (si.getSourceCard().isValid(cost.getType().split(";"), source.getController(), source)) {
        chosen.add(sp);
      }
    }
    return chosen.isEmpty() ? null : PaymentDecision.spellabilities(chosen);
  }
  @Override
  protected boolean canPlayAI(Player ai, SpellAbility sa) {
    final TargetRestrictions tgt = sa.getTargetRestrictions();
    final Card source = sa.getHostCard();
    final Game game = source.getGame();

    boolean useAbility = true;

    //        if (card.getController().isComputer()) {
    //            final List<Card> creatures = AllZoneUtil.getCreaturesInPlay();
    //            if (!creatures.isEmpty()) {
    //                cardToCopy = CardFactoryUtil.getBestCreatureAI(creatures);
    //            }
    //        }

    // TODO - add some kind of check to answer
    // "Am I going to attack with this?"
    // TODO - add some kind of check for during human turn to answer
    // "Can I use this to block something?"

    PhaseHandler phase = game.getPhaseHandler();
    // don't use instant speed clone abilities outside computers
    // Combat_Begin step
    if (!phase.is(PhaseType.COMBAT_BEGIN)
        && phase.isPlayerTurn(ai)
        && !SpellAbilityAi.isSorcerySpeed(sa)
        && !sa.hasParam("ActivationPhases")
        && !sa.hasParam("Permanent")) {
      return false;
    }

    // don't use instant speed clone abilities outside humans
    // Combat_Declare_Attackers_InstantAbility step
    if (!phase.is(PhaseType.COMBAT_DECLARE_ATTACKERS)
        || phase.isPlayerTurn(ai)
        || game.getCombat().getAttackers().isEmpty()) {
      return false;
    }

    // don't activate during main2 unless this effect is permanent
    if (phase.is(PhaseType.MAIN2) && !sa.hasParam("Permanent")) {
      return false;
    }

    if (null == tgt) {
      final List<Card> defined = AbilityUtils.getDefinedCards(source, sa.getParam("Defined"), sa);

      boolean bFlag = false;
      for (final Card c : defined) {
        bFlag |= (!c.isCreature() && !c.isTapped() && !(c.getTurnInZone() == phase.getTurn()));

        // for creatures that could be improved (like Figure of Destiny)
        if (c.isCreature() && (sa.hasParam("Permanent") || (!c.isTapped() && !c.isSick()))) {
          int power = -5;
          if (sa.hasParam("Power")) {
            power = AbilityUtils.calculateAmount(source, sa.getParam("Power"), sa);
          }
          int toughness = -5;
          if (sa.hasParam("Toughness")) {
            toughness = AbilityUtils.calculateAmount(source, sa.getParam("Toughness"), sa);
          }
          if ((power + toughness) > (c.getCurrentPower() + c.getCurrentToughness())) {
            bFlag = true;
          }
        }
      }

      if (!bFlag) { // All of the defined stuff is cloned, not very
        // useful
        return false;
      }
    } else {
      sa.resetTargets();
      useAbility &= cloneTgtAI(sa);
    }

    return useAbility;
  } // end cloneCanPlayAI()
Exemple #3
0
 /* (non-Javadoc)
  * @see forge.card.cost.CostPartWithList#executePayment(forge.card.spellability.SpellAbility, forge.Card)
  */
 @Override
 protected Card doPayment(SpellAbility ability, Card targetCard) {
   return targetCard.getGame().getAction().moveToHand(targetCard);
 }
  @Override
  public void resolve(SpellAbility sa) {
    final Card card = sa.getHostCard();
    final Game game = card.getGame();

    final boolean remDestroyed = sa.hasParam("RememberDestroyed");
    final boolean remAttached = sa.hasParam("RememberAttached");
    if (remDestroyed || remAttached) {
      card.clearRemembered();
    }

    final boolean noRegen = sa.hasParam("NoRegen");
    final boolean sac = sa.hasParam("Sacrifice");

    final List<Card> tgtCards = getTargetCards(sa);
    final List<Card> untargetedCards = new ArrayList<Card>();

    final TargetRestrictions tgt = sa.getTargetRestrictions();

    if (sa.hasParam("Radiance")) {
      for (final Card c :
          CardUtil.getRadiance(card, tgtCards.get(0), sa.getParam("ValidTgts").split(","))) {
        untargetedCards.add(c);
      }
    }

    for (final Card tgtC : tgtCards) {
      if (tgtC.isInPlay() && ((tgt == null) || tgtC.canBeTargetedBy(sa))) {
        boolean destroyed = false;
        final Card lki = CardUtil.getLKICopy(tgtC);
        if (remAttached) {
          card.addRemembered(tgtC.getEnchantedBy(false));
          card.addRemembered(tgtC.getEquippedBy(false));
          card.addRemembered(tgtC.getFortifiedBy(false));
        }
        if (sac) {
          destroyed = game.getAction().sacrifice(tgtC, sa) != null;
        } else if (noRegen) {
          destroyed = game.getAction().destroyNoRegeneration(tgtC, sa);
        } else {
          destroyed = game.getAction().destroy(tgtC, sa);
        }
        if (destroyed && remDestroyed) {
          card.addRemembered(tgtC);
        }
        if (destroyed && sa.hasParam("RememberLKI")) {
          card.addRemembered(lki);
        }
      }
    }

    for (final Card unTgtC : untargetedCards) {
      if (unTgtC.isInPlay()) {
        boolean destroyed = false;
        if (sac) {
          destroyed = game.getAction().sacrifice(unTgtC, sa) != null;
        } else if (noRegen) {
          destroyed = game.getAction().destroyNoRegeneration(unTgtC, sa);
        } else {
          destroyed = game.getAction().destroy(unTgtC, sa);
        }
        if (destroyed && remDestroyed) {
          card.addRemembered(unTgtC);
        }
      }
    }
  }
 /* (non-Javadoc)
  * @see forge.card.abilityfactory.SpellEffect#resolve(java.util.Map, forge.card.spellability.SpellAbility)
  */
 @Override
 public void resolve(final SpellAbility sa) {
   final Card source = sa.getHostCard();
   final Game game = source.getGame();
   game.reverseTurnOrder();
 }
  @Override
  public void resolve(SpellAbility sa) {
    final Card card = sa.getHostCard();
    // final int min = sa.containsKey("Min") ? Integer.parseInt(sa.get("Min")) : 0;
    // final int max = sa.containsKey("Max") ? Integer.parseInt(sa.get("Max")) : 99;
    final boolean random = sa.hasParam("Random");
    final boolean anyNumber = sa.hasParam("ChooseAnyNumber");
    final boolean secretlyChoose = sa.hasParam("SecretlyChoose");

    final String sMin = sa.getParamOrDefault("Min", "0");
    final int min = AbilityUtils.calculateAmount(card, sMin, sa);
    final String sMax = sa.getParamOrDefault("Max", "99");
    final int max = AbilityUtils.calculateAmount(card, sMax, sa);

    final List<Player> tgtPlayers = getTargetPlayers(sa);
    final TargetRestrictions tgt = sa.getTargetRestrictions();
    final Map<Player, Integer> chooseMap = new HashMap<Player, Integer>();

    for (final Player p : tgtPlayers) {
      if ((tgt == null) || p.canBeTargetedBy(sa)) {
        int chosen;
        if (random) {
          final Random randomGen = new Random();
          chosen = randomGen.nextInt(max - min) + min;
          p.getGame().getAction().nofityOfValue(sa, p, Integer.toString(chosen), null);
        } else {
          String title = sa.hasParam("ListTitle") ? sa.getParam("ListTitle") : "Choose a number";
          if (anyNumber) {
            chosen = p.getController().announceRequirements(sa, title, true);
          } else {
            chosen = p.getController().chooseNumber(sa, title, min, max);
          }
          // don't notify here, because most scripts I've seen don't store that number in a long
          // term
        }
        if (secretlyChoose) {
          chooseMap.put(p, chosen);
        } else {
          card.setChosenNumber(chosen);
        }
        if (sa.hasParam("Notify")) {
          p.getGame().getAction().nofityOfValue(sa, card, p.getName() + " picked " + chosen, p);
        }
      }
    }
    if (secretlyChoose) {
      StringBuilder sb = new StringBuilder();
      List<Player> highestNum = new ArrayList<Player>();
      List<Player> lowestNum = new ArrayList<Player>();
      int highest = 0;
      int lowest = Integer.MAX_VALUE;
      for (Entry<Player, Integer> ev : chooseMap.entrySet()) {
        int num = ev.getValue();
        Player player = ev.getKey();
        sb.append(player).append(" chose ").append(num);
        sb.append("\r\n");
        if (num > highest) {
          highestNum.clear();
          highest = num;
        }
        if (num == highest) {
          highestNum.add(player);
        }
        if (num < lowest) {
          lowestNum.clear();
          lowest = num;
        }
        if (num == lowest) {
          lowestNum.add(player);
        }
      }
      card.getGame().getAction().nofityOfValue(sa, card, sb.toString(), null);
      if (sa.hasParam("ChooseNumberSubAbility")) {
        SpellAbility sub =
            AbilityFactory.getAbility(card.getSVar(sa.getParam("ChooseNumberSubAbility")), card);
        sub.setActivatingPlayer(sa.getActivatingPlayer());
        ((AbilitySub) sub).setParent(sa);
        for (Player p : chooseMap.keySet()) {
          card.addRemembered(p);
          card.setChosenNumber(chooseMap.get(p));
          AbilityUtils.resolve(sub);
          card.clearRemembered();
        }
      }

      if (sa.hasParam("Lowest")) {
        SpellAbility action = AbilityFactory.getAbility(card.getSVar(sa.getParam("Lowest")), card);
        action.setActivatingPlayer(sa.getActivatingPlayer());
        ((AbilitySub) action).setParent(sa);
        for (Player p : lowestNum) {
          card.addRemembered(p);
          card.setChosenNumber(lowest);
          AbilityUtils.resolve(action);
          card.clearRemembered();
        }
      }
      if (sa.hasParam("Highest")) {
        SpellAbility action = AbilityFactory.getAbility(card.getSVar(sa.getParam("Highest")), card);
        action.setActivatingPlayer(sa.getActivatingPlayer());
        ((AbilitySub) action).setParent(sa);
        for (Player p : highestNum) {
          card.addRemembered(p);
          card.setChosenNumber(highest);
          AbilityUtils.resolve(action);
          card.clearRemembered();
        }
        if (sa.hasParam("RememberHighest")) {
          card.addRemembered(highestNum);
        }
      }
    }
  }
  /** {@inheritDoc} */
  @Override
  public final boolean performTest(final java.util.Map<String, Object> runParams2) {
    final SpellAbility spellAbility = (SpellAbility) runParams2.get("CastSA");
    if (spellAbility == null) {
      System.out.println(
          "TriggerSpellAbilityCast performTest encountered spellAbility == null. runParams2 = "
              + runParams2);
      return false;
    }
    final Card cast = spellAbility.getHostCard();
    final Game game = cast.getGame();
    final SpellAbilityStackInstance si = game.getStack().getInstanceFromSpellAbility(spellAbility);

    if (this.getMode() == TriggerType.SpellCast) {
      if (!spellAbility.isSpell()) {
        return false;
      }
    } else if (this.getMode() == TriggerType.AbilityCast) {
      if (!spellAbility.isAbility()) {
        return false;
      }
    } else if (this.getMode() == TriggerType.SpellAbilityCast) {
      // Empty block for readability.
    }

    if (this.mapParams.containsKey("ActivatedOnly")) {
      if (spellAbility.isTrigger()) {
        return false;
      }
    }

    if (this.mapParams.containsKey("ValidControllingPlayer")) {
      if (!matchesValid(
          cast.getController(),
          this.mapParams.get("ValidControllingPlayer").split(","),
          this.getHostCard())) {
        return false;
      }
    }

    if (this.mapParams.containsKey("ValidActivatingPlayer")) {
      if (si == null
          || !matchesValid(
              si.getSpellAbility(true).getActivatingPlayer(),
              this.mapParams.get("ValidActivatingPlayer").split(","),
              this.getHostCard())) {
        return false;
      }
      if (this.mapParams.containsKey("ActivatorThisTurnCast")) {
        String compare = this.mapParams.get("ActivatorThisTurnCast");
        List<Card> thisTurnCast =
            CardUtil.getThisTurnCast(
                this.mapParams.containsKey("ValidCard") ? this.mapParams.get("ValidCard") : "Card",
                this.getHostCard());
        thisTurnCast =
            CardLists.filterControlledBy(
                thisTurnCast, si.getSpellAbility(true).getActivatingPlayer());
        int left = thisTurnCast.size();
        int right = Integer.parseInt(compare.substring(2));
        if (!Expressions.compare(left, compare, right)) {
          return false;
        }
      }
    }

    if (this.mapParams.containsKey("ValidCard")) {
      if (!matchesValid(cast, this.mapParams.get("ValidCard").split(","), this.getHostCard())) {
        return false;
      }
    }

    if (this.mapParams.containsKey("TargetsValid")) {
      SpellAbility sa = spellAbility;
      if (si != null) {
        sa = si.getSpellAbility(true);
      }

      boolean validTgtFound = false;
      while (sa != null && !validTgtFound) {
        for (final Card tgt : sa.getTargets().getTargetCards()) {
          if (tgt.isValid(
              this.mapParams.get("TargetsValid").split(","),
              this.getHostCard().getController(),
              this.getHostCard())) {
            validTgtFound = true;
            break;
          }
        }

        for (final Player p : sa.getTargets().getTargetPlayers()) {
          if (matchesValid(p, this.mapParams.get("TargetsValid").split(","), this.getHostCard())) {
            validTgtFound = true;
            break;
          }
        }
        sa = sa.getSubAbility();
      }
      if (!validTgtFound) {
        return false;
      }
    }

    if (this.mapParams.containsKey("NonTapCost")) {
      final Cost cost = (Cost) (runParams2.get("Cost"));
      if (cost.hasTapCost()) {
        return false;
      }
    }

    if (this.mapParams.containsKey("Conspire")) {
      if (!spellAbility.isOptionalCostPaid(OptionalCost.Conspire)) {
        return false;
      }
      if (spellAbility.getConspireInstances() == 0) {
        return false;
      } else {
        spellAbility.subtractConspireInstance();
        // System.out.println("Conspire instances left = " + spellAbility.getConspireInstances());
      }
    }

    if (this.mapParams.containsKey("Outlast")) {
      if (!spellAbility.isOutlast()) {
        return false;
      }
    }

    if (this.mapParams.containsKey("IsSingleTarget")) {
      int numTargeted = 0;
      for (TargetChoices tc : spellAbility.getAllTargetChoices()) {
        numTargeted += tc.getNumTargeted();
      }
      if (numTargeted != 1) {
        return false;
      }
    }

    if (this.mapParams.containsKey("SpellSpeed")) {
      if (this.mapParams.get("SpellSpeed").equals("NotSorcerySpeed")) {
        if (this.getHostCard().getController().couldCastSorcery(spellAbility)) {
          return false;
        }
        if (this.getHostCard()
            .hasKeyword(
                "You may cast CARDNAME as though it had flash. If you cast it any time a "
                    + "sorcery couldn't have been cast, the controller of the permanent it becomes sacrifices it at the beginning"
                    + " of the next cleanup step.")) {
          // for these cards the trigger must only fire if using their own ability to cast at
          // instant speed
          if (this.getHostCard().hasKeyword("Flash")
              || this.getHostCard()
                  .getController()
                  .hasKeyword("You may cast nonland cards as though they had flash.")) {
            return false;
          }
        }
        return true;
      }
    }

    return true;
  }
  /* (non-Javadoc)
   * @see forge.card.ability.SpellAbilityEffect#resolve(forge.card.spellability.SpellAbility)
   */
  @Override
  public void resolve(final SpellAbility sa) {
    final Card hostCard = sa.getHostCard();
    final Game game = hostCard.getGame();
    final List<String> keywords = new ArrayList<String>();
    final List<String> types = new ArrayList<String>();
    final List<String> svars = new ArrayList<String>();
    final List<String> triggers = new ArrayList<String>();
    if (sa.hasParam("Optional")) {
      if (!sa.getActivatingPlayer()
          .getController()
          .confirmAction(sa, null, "Copy this permanent?")) {
        return;
      }
    }
    if (sa.hasParam("Keywords")) {
      keywords.addAll(Arrays.asList(sa.getParam("Keywords").split(" & ")));
    }
    if (sa.hasParam("AddTypes")) {
      types.addAll(Arrays.asList(sa.getParam("AddTypes").split(" & ")));
    }
    if (sa.hasParam("AddSVars")) {
      svars.addAll(Arrays.asList(sa.getParam("AddSVars").split(" & ")));
    }
    if (sa.hasParam("Triggers")) {
      triggers.addAll(Arrays.asList(sa.getParam("Triggers").split(" & ")));
    }
    final int numCopies =
        sa.hasParam("NumCopies")
            ? AbilityUtils.calculateAmount(hostCard, sa.getParam("NumCopies"), sa)
            : 1;

    Player controller = null;
    if (sa.hasParam("Controller")) {
      final FCollectionView<Player> defined =
          AbilityUtils.getDefinedPlayers(hostCard, sa.getParam("Controller"), sa);
      if (!defined.isEmpty()) {
        controller = defined.getFirst();
      }
    }
    if (controller == null) {
      controller = sa.getActivatingPlayer();
    }

    List<Card> tgtCards = getTargetCards(sa);
    final TargetRestrictions tgt = sa.getTargetRestrictions();

    if (sa.hasParam("ValidSupportedCopy")) {
      List<PaperCard> cards =
          Lists.newArrayList(StaticData.instance().getCommonCards().getUniqueCards());
      String valid = sa.getParam("ValidSupportedCopy");
      if (valid.contains("X")) {
        valid =
            valid.replace("X", Integer.toString(AbilityUtils.calculateAmount(hostCard, "X", sa)));
      }
      if (StringUtils.containsIgnoreCase(valid, "creature")) {
        Predicate<PaperCard> cpp =
            Predicates.compose(CardRulesPredicates.Presets.IS_CREATURE, PaperCard.FN_GET_RULES);
        cards = Lists.newArrayList(Iterables.filter(cards, cpp));
      }
      if (StringUtils.containsIgnoreCase(valid, "equipment")) {
        Predicate<PaperCard> cpp =
            Predicates.compose(CardRulesPredicates.Presets.IS_EQUIPMENT, PaperCard.FN_GET_RULES);
        cards = Lists.newArrayList(Iterables.filter(cards, cpp));
      }
      if (sa.hasParam("RandomCopied")) {
        List<PaperCard> copysource = new ArrayList<PaperCard>(cards);
        List<Card> choice = new ArrayList<Card>();
        final String num = sa.hasParam("RandomNum") ? sa.getParam("RandomNum") : "1";
        int ncopied = AbilityUtils.calculateAmount(hostCard, num, sa);
        while (ncopied > 0) {
          final PaperCard cp = Aggregates.random(copysource);
          Card possibleCard =
              Card.fromPaperCard(
                  cp,
                  sa.getActivatingPlayer()); // Need to temporarily set the Owner so the Game is set

          if (possibleCard.isValid(valid, hostCard.getController(), hostCard)) {
            choice.add(possibleCard);
            copysource.remove(cp);
            ncopied -= 1;
          }
        }
        tgtCards = choice;
      } else if (sa.hasParam("DefinedName")) {
        String name = sa.getParam("DefinedName");
        if (name.equals("NamedCard")) {
          if (!hostCard.getNamedCard().isEmpty()) {
            name = hostCard.getNamedCard();
          }
        }

        Predicate<PaperCard> cpp =
            Predicates.compose(
                CardRulesPredicates.name(StringOp.EQUALS, name), PaperCard.FN_GET_RULES);
        cards = Lists.newArrayList(Iterables.filter(cards, cpp));

        tgtCards.clear();
        if (!cards.isEmpty()) {
          tgtCards.add(Card.fromPaperCard(cards.get(0), controller));
        }
      }
    }
    hostCard.clearClones();

    for (final Card c : tgtCards) {
      if ((tgt == null) || c.canBeTargetedBy(sa)) {

        int multiplier = numCopies * hostCard.getController().getTokenDoublersMagnitude();
        final List<Card> crds = new ArrayList<Card>(multiplier);

        for (int i = 0; i < multiplier; i++) {
          final Card copy = CardFactory.copyCopiableCharacteristics(c, sa.getActivatingPlayer());
          copy.setToken(true);
          copy.setCopiedPermanent(c);
          CardFactory.copyCopiableAbilities(c, copy);
          // add keywords from sa
          for (final String kw : keywords) {
            copy.addIntrinsicKeyword(kw);
          }
          for (final String type : types) {
            copy.addType(type);
          }
          for (final String svar : svars) {
            String actualsVar = hostCard.getSVar(svar);
            String name = svar;
            if (actualsVar.startsWith("SVar:")) {
              actualsVar = actualsVar.split("SVar:")[1];
              name = actualsVar.split(":")[0];
              actualsVar = actualsVar.split(":")[1];
            }
            copy.setSVar(name, actualsVar);
          }
          for (final String s : triggers) {
            final String actualTrigger = hostCard.getSVar(s);
            final Trigger parsedTrigger = TriggerHandler.parseTrigger(actualTrigger, copy, true);
            copy.addTrigger(parsedTrigger);
          }

          // Temporarily register triggers of an object created with CopyPermanent
          // game.getTriggerHandler().registerActiveTrigger(copy, false);
          final Card copyInPlay = game.getAction().moveToPlay(copy);

          // when copying something stolen:
          copyInPlay.setController(controller, 0);
          copyInPlay.setSetCode(c.getSetCode());

          copyInPlay.setCloneOrigin(hostCard);
          sa.getHostCard().addClone(copyInPlay);
          crds.add(copyInPlay);
          if (sa.hasParam("RememberCopied")) {
            hostCard.addRemembered(copyInPlay);
          }
          if (sa.hasParam("Tapped")) {
            copyInPlay.setTapped(true);
          }
          if (sa.hasParam("CopyAttacking") && game.getPhaseHandler().inCombat()) {
            final String attacked = sa.getParam("CopyAttacking");
            GameEntity defender;
            if ("True".equals(attacked)) {
              FCollectionView<GameEntity> defs = game.getCombat().getDefenders();
              defender =
                  c.getController()
                      .getController()
                      .chooseSingleEntityForEffect(
                          defs, sa, "Choose which defender to attack with " + c, false);
            } else {
              defender =
                  AbilityUtils.getDefinedPlayers(hostCard, sa.getParam("CopyAttacking"), sa).get(0);
            }
            game.getCombat().addAttacker(copyInPlay, defender);
            game.fireEvent(new GameEventCombatChanged());
          }

          if (sa.hasParam("AttachedTo")) {
            CardCollectionView list =
                AbilityUtils.getDefinedCards(hostCard, sa.getParam("AttachedTo"), sa);
            if (list.isEmpty()) {
              list = copyInPlay.getController().getGame().getCardsIn(ZoneType.Battlefield);
              list =
                  CardLists.getValidCards(
                      list, sa.getParam("AttachedTo"), copyInPlay.getController(), copyInPlay);
            }
            if (!list.isEmpty()) {
              Card attachedTo =
                  sa.getActivatingPlayer()
                      .getController()
                      .chooseSingleEntityForEffect(
                          list, sa, copyInPlay + " - Select a card to attach to.");
              if (copyInPlay.isAura()) {
                if (attachedTo.canBeEnchantedBy(copyInPlay)) {
                  copyInPlay.enchantEntity(attachedTo);
                } else { // can't enchant
                  continue;
                }
              } else if (copyInPlay.isEquipment()) { // Equipment
                if (attachedTo.canBeEquippedBy(copyInPlay)) {
                  copyInPlay.equipCard(attachedTo);
                } else {
                  continue;
                }
              } else { // Fortification
                copyInPlay.fortifyCard(attachedTo);
              }
            } else {
              continue;
            }
          }
        }

        if (sa.hasParam("AtEOT")) {
          final String location = sa.getParam("AtEOT");
          registerDelayedTrigger(sa, location, crds);
        }
      } // end canBeTargetedBy
    } // end foreach Card
  } // end resolve