package forge.card.abilityFactory; import forge.*; import forge.card.cardFactory.CardFactory; import forge.card.cardFactory.CardFactoryUtil; import forge.card.spellability.*; import forge.card.trigger.Trigger; import forge.gui.GuiUtils; import java.util.*; /** * <p>AbilityFactory_Copy class.</p> * * @author Forge * @version $Id: $ */ public class AbilityFactory_Copy { // ************************************************************************* // ************************* CopyPermanent ********************************* // ************************************************************************* /** * <p>createAbilityCopyPermanent.</p> * * @param af a {@link forge.card.abilityFactory.AbilityFactory} object. * @return a {@link forge.card.spellability.SpellAbility} object. */ public static SpellAbility createAbilityCopyPermanent(final AbilityFactory af) { final SpellAbility abCopyPermanent = new Ability_Activated(af.getHostCard(), af.getAbCost(), af.getAbTgt()) { private static final long serialVersionUID = 4557071554433108024L; @Override public String getStackDescription() { return copyPermanentStackDescription(af, this); } @Override public boolean canPlayAI() { return copyPermanentCanPlayAI(af, this); } @Override public void resolve() { copyPermanentResolve(af, this); } @Override public boolean doTrigger(boolean mandatory) { return copyPermanentTriggerAI(af, this, mandatory); } }; return abCopyPermanent; } /** * <p>createSpellCopyPermanent.</p> * * @param af a {@link forge.card.abilityFactory.AbilityFactory} object. * @return a {@link forge.card.spellability.SpellAbility} object. */ public static SpellAbility createSpellCopyPermanent(final AbilityFactory af) { final SpellAbility spCopyPermanent = new Spell(af.getHostCard(), af.getAbCost(), af.getAbTgt()) { private static final long serialVersionUID = 3313370358993251728L; @Override public String getStackDescription() { return copyPermanentStackDescription(af, this); } @Override public boolean canPlayAI() { return copyPermanentCanPlayAI(af, this); } @Override public void resolve() { copyPermanentResolve(af, this); } }; return spCopyPermanent; } /** * <p>createDrawbackCopyPermanent.</p> * * @param af a {@link forge.card.abilityFactory.AbilityFactory} object. * @return a {@link forge.card.spellability.SpellAbility} object. */ public static SpellAbility createDrawbackCopyPermanent(final AbilityFactory af) { final SpellAbility dbCopyPermanent = new Ability_Sub(af.getHostCard(), af.getAbTgt()) { private static final long serialVersionUID = -7725564505830285184L; @Override public String getStackDescription() { return copyPermanentStackDescription(af, this); } @Override public void resolve() { copyPermanentResolve(af, this); } @Override public boolean chkAI_Drawback() { return true; } @Override public boolean doTrigger(boolean mandatory) { return copyPermanentTriggerAI(af, this, mandatory); } }; return dbCopyPermanent; } /** * <p>copyPermanentStackDescription.</p> * * @param af a {@link forge.card.abilityFactory.AbilityFactory} object. * @param sa a {@link forge.card.spellability.SpellAbility} object. * @return a {@link java.lang.String} object. */ private static String copyPermanentStackDescription(AbilityFactory af, SpellAbility sa) { StringBuilder sb = new StringBuilder(); HashMap<String, String> params = af.getMapParams(); if (!(sa instanceof Ability_Sub)) sb.append(sa.getSourceCard()).append(" - "); else sb.append(" "); ArrayList<Card> tgtCards; Target tgt = af.getAbTgt(); if (tgt != null) tgtCards = tgt.getTargetCards(); else tgtCards = AbilityFactory.getDefinedCards(sa.getSourceCard(), params.get("Defined"), sa); sb.append("Copy "); Iterator<Card> it = tgtCards.iterator(); while (it.hasNext()) { sb.append(it.next()); if (it.hasNext()) sb.append(", "); } sb.append("."); Ability_Sub abSub = sa.getSubAbility(); if (abSub != null) { sb.append(abSub.getStackDescription()); } return sb.toString(); } /** * <p>copyPermanentCanPlayAI.</p> * * @param af a {@link forge.card.abilityFactory.AbilityFactory} object. * @param sa a {@link forge.card.spellability.SpellAbility} object. * @return a boolean. */ private static boolean copyPermanentCanPlayAI(final AbilityFactory af, final SpellAbility sa) { Card source = sa.getSourceCard(); //TODO - I'm sure someone can do this AI better HashMap<String, String> params = af.getMapParams(); if (params.containsKey("AtEOT") && !AllZone.getPhase().is(Constant.Phase.Main1)) { return false; } else { double chance = .4; // 40 percent chance with instant speed stuff if (AbilityFactory.isSorcerySpeed(sa)) chance = .667; // 66.7% chance for sorcery speed (since it will never activate EOT) Random r = MyRandom.random; if (r.nextFloat() <= Math.pow(chance, source.getAbilityUsed() + 1)) return copyPermanentTriggerAI(af, sa, false); else return false; } } /** * <p>copyPermanentTriggerAI.</p> * * @param af a {@link forge.card.abilityFactory.AbilityFactory} object. * @param sa a {@link forge.card.spellability.SpellAbility} object. * @param mandatory a boolean. * @return a boolean. */ private static boolean copyPermanentTriggerAI(final AbilityFactory af, final SpellAbility sa, boolean mandatory) { //HashMap<String,String> params = af.getMapParams(); Card source = sa.getSourceCard(); if (!ComputerUtil.canPayCost(sa) && !mandatory) return false; ////// // Targeting Target abTgt = sa.getTarget(); if (abTgt != null) { CardList list = AllZoneUtil.getCardsInPlay(); list = list.getValidCards(abTgt.getValidTgts(), source.getController(), source); abTgt.resetTargets(); // target loop while (abTgt.getNumTargeted() < abTgt.getMaxTargets(sa.getSourceCard(), sa)) { if (list.size() == 0) { if (abTgt.getNumTargeted() < abTgt.getMinTargets(sa.getSourceCard(), sa) || abTgt.getNumTargeted() == 0) { abTgt.resetTargets(); return false; } else { // TODO is this good enough? for up to amounts? break; } } Card choice; if (list.filter(AllZoneUtil.creatures).size() > 0) { choice = CardFactoryUtil.AI_getBestCreature(list); } else { choice = CardFactoryUtil.AI_getMostExpensivePermanent(list, source, true); } if (choice == null) { // can't find anything left if (abTgt.getNumTargeted() < abTgt.getMinTargets(sa.getSourceCard(), sa) || abTgt.getNumTargeted() == 0) { abTgt.resetTargets(); return false; } else { // TODO is this good enough? for up to amounts? break; } } list.remove(choice); abTgt.addTarget(choice); } } else { //if no targeting, it should always be ok } //end Targeting if (af.hasSubAbility()) { Ability_Sub abSub = sa.getSubAbility(); if (abSub != null) { return abSub.chkAI_Drawback(); } } return true; } /** * <p>copyPermanentResolve.</p> * * @param af a {@link forge.card.abilityFactory.AbilityFactory} object. * @param sa a {@link forge.card.spellability.SpellAbility} object. */ private static void copyPermanentResolve(final AbilityFactory af, final SpellAbility sa) { final HashMap<String, String> params = af.getMapParams(); Card hostCard = af.getHostCard(); ArrayList<String> keywords = new ArrayList<String>(); if (params.containsKey("Keywords")) { keywords.addAll(Arrays.asList(params.get("Keywords").split(" & "))); } int numCopies = params.containsKey("NumCopies") ? AbilityFactory.calculateAmount(hostCard, params.get("NumCopies"), sa) : 1; ArrayList<Card> tgtCards; Target tgt = af.getAbTgt(); if (tgt != null) tgtCards = tgt.getTargetCards(); else tgtCards = AbilityFactory.getDefinedCards(sa.getSourceCard(), params.get("Defined"), sa); hostCard.clearClones(); for (Card c : tgtCards) { if (tgt == null || CardFactoryUtil.canTarget(hostCard, c)) { //start copied Kiki code int multiplier = AllZoneUtil.getDoublingSeasonMagnitude(hostCard.getController()); multiplier *= numCopies; Card[] crds = new Card[multiplier]; for (int i = 0; i < multiplier; i++) { //TODO: Use central copy methods Card copy; if (!c.isToken()) { //copy creature and put it onto the battlefield copy = AllZone.getCardFactory().getCard(c.getName(), sa.getActivatingPlayer()); //when copying something stolen: copy.setController(sa.getActivatingPlayer()); copy.setToken(true); copy.setCopiedToken(true); } else { //isToken() copy = CardFactory.copyStats(c); copy.setName(c.getName()); copy.setImageName(c.getImageName()); copy.setOwner(sa.getActivatingPlayer()); copy.setController(sa.getActivatingPlayer()); copy.setManaCost(c.getManaCost()); copy.setColor(c.getColor()); copy.setToken(true); copy.setType(c.getType()); copy.setBaseAttack(c.getBaseAttack()); copy.setBaseDefense(c.getBaseDefense()); } //add keywords from params for (String kw : keywords) { copy.addIntrinsicKeyword(kw); } //Slight hack in case we copy a creature with triggers. for (Trigger t : copy.getTriggers()) { AllZone.getTriggerHandler().registerTrigger(t); } copy.setCurSetCode(c.getCurSetCode()); copy.setImageFilename(c.getImageFilename()); if (c.isFaceDown()) { copy.setIsFaceDown(true); copy.setManaCost(""); copy.setBaseAttack(2); copy.setBaseDefense(2); copy.setIntrinsicKeyword(new ArrayList<String>()); //remove all keywords copy.setType(new ArrayList<String>()); //remove all types copy.addType("Creature"); copy.clearSpellAbility(); //disallow "morph_up" copy.setCurSetCode(""); copy.setImageFilename("morph.jpg"); } copy = AllZone.getGameAction().moveToPlay(copy); copy.setCloneOrigin(hostCard); sa.getSourceCard().addClone(copy); crds[i] = copy; } //have to do this since getTargetCard() might change //if Kiki-Jiki somehow gets untapped again final Card[] target = new Card[multiplier]; for (int i = 0; i < multiplier; i++) { final int index = i; target[index] = crds[index]; final SpellAbility sac = new Ability(target[index], "0") { @Override public void resolve() { //technically your opponent could steal the token //and the token shouldn't be sacrificed if (AllZoneUtil.isCardInPlay(target[index])) { if (params.get("AtEOT").equals("Sacrifice")) { AllZone.getGameAction().sacrifice(target[index]); //maybe do a setSacrificeAtEOT, but probably not. } else if (params.get("AtEOT").equals("Exile")) { AllZone.getGameAction().exile(target[index]); } //Slight hack in case we copy a creature with triggers AllZone.getTriggerHandler().removeAllFromCard(target[index]); } } }; Command atEOT = new Command() { private static final long serialVersionUID = -4184510100801568140L; public void execute() { sac.setStackDescription(params.get("AtEOT") + " " + target[index] + "."); AllZone.getStack().addSimultaneousStackEntry(sac); } };//Command if (params.containsKey("AtEOT")) { AllZone.getEndOfTurn().addAt(atEOT); } //end copied Kiki code } }//end canTarget }//end foreach Card }//end resolve // ************************************************************************* // ************************* CopySpell ************************************* // ************************************************************************* /** * <p>createAbilityCopySpell.</p> * * @param af a {@link forge.card.abilityFactory.AbilityFactory} object. * @return a {@link forge.card.spellability.SpellAbility} object. */ public static SpellAbility createAbilityCopySpell(final AbilityFactory af) { final SpellAbility abCopySpell = new Ability_Activated(af.getHostCard(), af.getAbCost(), af.getAbTgt()) { private static final long serialVersionUID = 5232548517225345052L; @Override public String getStackDescription() { return copySpellStackDescription(af, this); } @Override public boolean canPlayAI() { return copySpellCanPlayAI(af, this); } @Override public void resolve() { copySpellResolve(af, this); } @Override public boolean doTrigger(boolean mandatory) { return copySpellTriggerAI(af, this, mandatory); } }; return abCopySpell; } /** * <p>createSpellCopySpell.</p> * * @param af a {@link forge.card.abilityFactory.AbilityFactory} object. * @return a {@link forge.card.spellability.SpellAbility} object. */ public static SpellAbility createSpellCopySpell(final AbilityFactory af) { final SpellAbility spCopySpell = new Spell(af.getHostCard(), af.getAbCost(), af.getAbTgt()) { private static final long serialVersionUID = 1878946074608916745L; @Override public String getStackDescription() { return copySpellStackDescription(af, this); } @Override public boolean canPlayAI() { return copySpellCanPlayAI(af, this); } @Override public void resolve() { copySpellResolve(af, this); } }; return spCopySpell; } /** * <p>createDrawbackCopySpell.</p> * * @param af a {@link forge.card.abilityFactory.AbilityFactory} object. * @return a {@link forge.card.spellability.SpellAbility} object. */ public static SpellAbility createDrawbackCopySpell(final AbilityFactory af) { final SpellAbility dbCopySpell = new Ability_Sub(af.getHostCard(), af.getAbTgt()) { private static final long serialVersionUID = 1927508119173644632L; @Override public String getStackDescription() { return copySpellStackDescription(af, this); } @Override public void resolve() { copySpellResolve(af, this); } @Override public boolean chkAI_Drawback() { return true; } @Override public boolean doTrigger(boolean mandatory) { return copySpellTriggerAI(af, this, mandatory); } }; return dbCopySpell; } /** * <p>copySpellStackDescription.</p> * * @param af a {@link forge.card.abilityFactory.AbilityFactory} object. * @param sa a {@link forge.card.spellability.SpellAbility} object. * @return a {@link java.lang.String} object. */ private static String copySpellStackDescription(AbilityFactory af, SpellAbility sa) { StringBuilder sb = new StringBuilder(); HashMap<String, String> params = af.getMapParams(); if (!(sa instanceof Ability_Sub)) sb.append(sa.getSourceCard().getName()).append(" - "); else sb.append(" "); ArrayList<SpellAbility> tgtSpells; Target tgt = af.getAbTgt(); if (tgt != null) tgtSpells = tgt.getTargetSAs(); else tgtSpells = AbilityFactory.getDefinedSpellAbilities(sa.getSourceCard(), params.get("Defined"), sa); sb.append("Copy "); // TODO Someone fix this Description when Copying Charms Iterator<SpellAbility> it = tgtSpells.iterator(); while (it.hasNext()) { sb.append(it.next().getSourceCard()); if (it.hasNext()) sb.append(", "); } sb.append("."); //TODO probably add an optional "You may choose new targets..." Ability_Sub abSub = sa.getSubAbility(); if (abSub != null) { sb.append(abSub.getStackDescription()); } return sb.toString(); } /** * <p>copySpellCanPlayAI.</p> * * @param af a {@link forge.card.abilityFactory.AbilityFactory} object. * @param sa a {@link forge.card.spellability.SpellAbility} object. * @return a boolean. */ private static boolean copySpellCanPlayAI(final AbilityFactory af, final SpellAbility sa) { return false; } /** * <p>copySpellTriggerAI.</p> * * @param af a {@link forge.card.abilityFactory.AbilityFactory} object. * @param sa a {@link forge.card.spellability.SpellAbility} object. * @param mandatory a boolean. * @return a boolean. */ private static boolean copySpellTriggerAI(final AbilityFactory af, final SpellAbility sa, boolean mandatory) { boolean randomReturn = false; if (af.hasSubAbility()) { Ability_Sub abSub = sa.getSubAbility(); if (abSub != null) { return randomReturn && abSub.chkAI_Drawback(); } } return randomReturn; } /** * <p>copySpellResolve.</p> * * @param af a {@link forge.card.abilityFactory.AbilityFactory} object. * @param sa a {@link forge.card.spellability.SpellAbility} object. */ private static void copySpellResolve(final AbilityFactory af, final SpellAbility sa) { final HashMap<String, String> params = af.getMapParams(); Card card = af.getHostCard(); ArrayList<SpellAbility> tgtSpells; Target tgt = af.getAbTgt(); if (tgt != null) tgtSpells = tgt.getTargetSAs(); else tgtSpells = AbilityFactory.getDefinedSpellAbilities(sa.getSourceCard(), params.get("Defined"), sa); if (tgtSpells.size() == 0) return; SpellAbility chosenSA = null; if (tgtSpells.size() == 1) chosenSA = tgtSpells.get(0); else if (sa.getActivatingPlayer().isHuman()) chosenSA = (SpellAbility) GuiUtils.getChoice("Select a spell to copy", tgtSpells.toArray()); else chosenSA = tgtSpells.get(0); if (tgt == null || CardFactoryUtil.canTarget(card, chosenSA.getSourceCard())) AllZone.getCardFactory().copySpellontoStack(card, chosenSA.getSourceCard(), chosenSA, true); }//end resolve }//end class AbilityFactory_Copy