@Override
 public PaymentDecision visit(CostChooseCreatureType cost) {
   String choice =
       player
           .getController()
           .chooseSomeType(
               "Creature",
               ability,
               new ArrayList<String>(CardType.getCreatureTypes()),
               new ArrayList<String>());
   return PaymentDecision.type(choice);
 }
  @Override
  public void resolve(final SpellAbility sa) {
    final Card host = sa.getHostCard();
    final Map<String, String> svars = host.getSVars();

    // AF specific sa
    int power = -1;
    if (sa.hasParam("Power")) {
      power = AbilityUtils.calculateAmount(host, sa.getParam("Power"), sa);
    }
    int toughness = -1;
    if (sa.hasParam("Toughness")) {
      toughness = AbilityUtils.calculateAmount(host, sa.getParam("Toughness"), sa);
    }
    final Game game = sa.getActivatingPlayer().getGame();

    // Every Animate event needs a unique time stamp
    final long timestamp = game.getNextTimestamp();

    final boolean permanent = sa.hasParam("Permanent");

    final CardType types = new CardType();
    if (sa.hasParam("Types")) {
      types.addAll(Arrays.asList(sa.getParam("Types").split(",")));
    }

    final CardType removeTypes = new CardType();
    if (sa.hasParam("RemoveTypes")) {
      removeTypes.addAll(Arrays.asList(sa.getParam("RemoveTypes").split(",")));
    }

    // allow ChosenType - overrides anything else specified
    if (types.hasSubtype("ChosenType")) {
      types.clear();
      types.add(host.getChosenType());
    }

    final List<String> keywords = new ArrayList<String>();
    if (sa.hasParam("Keywords")) {
      keywords.addAll(Arrays.asList(sa.getParam("Keywords").split(" & ")));
    }

    final List<String> removeKeywords = new ArrayList<String>();
    if (sa.hasParam("RemoveKeywords")) {
      removeKeywords.addAll(Arrays.asList(sa.getParam("RemoveKeywords").split(" & ")));
    }

    final List<String> hiddenKeywords = new ArrayList<String>();
    if (sa.hasParam("HiddenKeywords")) {
      hiddenKeywords.addAll(Arrays.asList(sa.getParam("HiddenKeywords").split(" & ")));
    }
    // allow SVar substitution for keywords
    for (int i = 0; i < keywords.size(); i++) {
      final String k = keywords.get(i);
      if (svars.containsKey(k)) {
        keywords.add(svars.get(k));
        keywords.remove(k);
      }
    }

    // colors to be added or changed to
    String tmpDesc = "";
    if (sa.hasParam("Colors")) {
      final String colors = sa.getParam("Colors");
      if (colors.equals("ChosenColor")) {
        tmpDesc = CardUtil.getShortColorsString(host.getChosenColors());
      } else {
        tmpDesc =
            CardUtil.getShortColorsString(new ArrayList<String>(Arrays.asList(colors.split(","))));
      }
    }
    final String finalDesc = tmpDesc;

    // abilities to add to the animated being
    final List<String> abilities = new ArrayList<String>();
    if (sa.hasParam("Abilities")) {
      abilities.addAll(Arrays.asList(sa.getParam("Abilities").split(",")));
    }
    // replacement effects to add to the animated being
    final List<String> replacements = new ArrayList<String>();
    if (sa.hasParam("Replacements")) {
      replacements.addAll(Arrays.asList(sa.getParam("Replacements").split(",")));
    }
    // triggers to add to the animated being
    final List<String> triggers = new ArrayList<String>();
    if (sa.hasParam("Triggers")) {
      triggers.addAll(Arrays.asList(sa.getParam("Triggers").split(",")));
    }

    // sVars to add to the animated being
    final List<String> sVars = new ArrayList<String>();
    if (sa.hasParam("sVars")) {
      sVars.addAll(Arrays.asList(sa.getParam("sVars").split(",")));
    }

    String valid = "";

    if (sa.hasParam("ValidCards")) {
      valid = sa.getParam("ValidCards");
    }

    CardCollectionView list;
    List<Player> tgtPlayers = getTargetPlayers(sa);

    if (!sa.usesTargeting() && !sa.hasParam("Defined")) {
      list = game.getCardsIn(ZoneType.Battlefield);
    } else {
      list = tgtPlayers.get(0).getCardsIn(ZoneType.Battlefield);
    }

    list = CardLists.getValidCards(list, valid.split(","), host.getController(), host);

    for (final Card c : list) {
      doAnimate(
          c,
          sa,
          power,
          toughness,
          types,
          removeTypes,
          finalDesc,
          keywords,
          removeKeywords,
          hiddenKeywords,
          timestamp);

      // give abilities
      final List<SpellAbility> addedAbilities = new ArrayList<SpellAbility>();
      if (abilities.size() > 0) {
        for (final String s : abilities) {
          final String actualAbility = host.getSVar(s);
          final SpellAbility grantedAbility = AbilityFactory.getAbility(actualAbility, c);
          addedAbilities.add(grantedAbility);
          c.addSpellAbility(grantedAbility);
        }
      }

      // remove abilities
      final List<SpellAbility> removedAbilities = new ArrayList<SpellAbility>();
      if (sa.hasParam("OverwriteAbilities") || sa.hasParam("RemoveAllAbilities")) {
        for (final SpellAbility ab : c.getSpellAbilities()) {
          if (ab.isAbility()) {
            c.removeSpellAbility(ab);
            removedAbilities.add(ab);
          }
        }
      }
      // give replacement effects
      final List<ReplacementEffect> addedReplacements = new ArrayList<ReplacementEffect>();
      if (replacements.size() > 0) {
        for (final String s : replacements) {
          final String actualReplacement = host.getSVar(s);
          final ReplacementEffect parsedReplacement =
              ReplacementHandler.parseReplacement(actualReplacement, c, false);
          addedReplacements.add(c.addReplacementEffect(parsedReplacement));
        }
      }
      // Grant triggers
      final List<Trigger> addedTriggers = new ArrayList<Trigger>();
      if (triggers.size() > 0) {
        for (final String s : triggers) {
          final String actualTrigger = host.getSVar(s);
          final Trigger parsedTrigger = TriggerHandler.parseTrigger(actualTrigger, c, false);
          addedTriggers.add(c.addTrigger(parsedTrigger));
        }
      }

      // suppress triggers from the animated card
      final List<Trigger> removedTriggers = new ArrayList<Trigger>();
      if (sa.hasParam("OverwriteTriggers") || sa.hasParam("RemoveAllAbilities")) {
        final FCollectionView<Trigger> triggersToRemove = c.getTriggers();
        for (final Trigger trigger : triggersToRemove) {
          trigger.setSuppressed(true);
          removedTriggers.add(trigger);
        }
      }

      // suppress static abilities from the animated card
      final List<StaticAbility> removedStatics = new ArrayList<StaticAbility>();
      if (sa.hasParam("OverwriteStatics") || sa.hasParam("RemoveAllAbilities")) {
        final FCollectionView<StaticAbility> staticsToRemove = c.getStaticAbilities();
        for (final StaticAbility stAb : staticsToRemove) {
          stAb.setTemporarilySuppressed(true);
          removedStatics.add(stAb);
        }
      }

      // suppress static abilities from the animated card
      final List<ReplacementEffect> removedReplacements = new ArrayList<ReplacementEffect>();
      if (sa.hasParam("OverwriteReplacements") || sa.hasParam("RemoveAllAbilities")) {
        final FCollectionView<ReplacementEffect> replacementsToRemove = c.getReplacementEffects();
        for (final ReplacementEffect re : replacementsToRemove) {
          re.setTemporarilySuppressed(true);
          removedReplacements.add(re);
        }
      }

      // give sVars
      if (sVars.size() > 0) {
        for (final String s : sVars) {
          final String actualsVar = host.getSVar(s);
          c.setSVar(s, actualsVar);
        }
      }
      game.fireEvent(new GameEventCardStatsChanged(c));

      final GameCommand unanimate =
          new GameCommand() {
            private static final long serialVersionUID = -5861759814760561373L;

            @Override
            public void run() {
              doUnanimate(
                  c,
                  sa,
                  finalDesc,
                  hiddenKeywords,
                  addedAbilities,
                  addedTriggers,
                  addedReplacements,
                  false,
                  removedAbilities,
                  timestamp);

              // give back suppressed triggers
              for (final Trigger t : removedTriggers) {
                t.setSuppressed(false);
              }

              // give back suppressed static abilities
              for (final StaticAbility s : removedStatics) {
                s.setTemporarilySuppressed(false);
              }

              // give back suppressed replacement effects
              for (final ReplacementEffect re : removedReplacements) {
                re.setTemporarilySuppressed(false);
              }
              game.fireEvent(new GameEventCardStatsChanged(c));
            }
          };

      if (!permanent) {
        if (sa.hasParam("UntilEndOfCombat")) {
          game.getEndOfCombat().addUntil(unanimate);
        } else {
          game.getEndOfTurn().addUntil(unanimate);
        }
      }
    }
  } // animateAllResolve