AF: Copy, repeat

This commit is contained in:
Maxmtg
2012-11-03 18:15:20 +00:00
parent b61cda6f63
commit ee911645d4
10 changed files with 827 additions and 1246 deletions

8
.gitattributes vendored
View File

@@ -12464,9 +12464,7 @@ src/main/java/forge/card/abilityfactory/AbilityFactoryAttach.java svneol=native#
src/main/java/forge/card/abilityfactory/AbilityFactoryChangeZone.java svneol=native#text/plain
src/main/java/forge/card/abilityfactory/AbilityFactoryCharm.java svneol=native#text/plain
src/main/java/forge/card/abilityfactory/AbilityFactoryCleanup.java svneol=native#text/plain
src/main/java/forge/card/abilityfactory/AbilityFactoryCopy.java svneol=native#text/plain
src/main/java/forge/card/abilityfactory/AbilityFactoryMana.java svneol=native#text/plain
src/main/java/forge/card/abilityfactory/AbilityFactoryRepeat.java -text
src/main/java/forge/card/abilityfactory/AbilityFactoryStoreSVar.java -text
src/main/java/forge/card/abilityfactory/CommonAbility.java -text
src/main/java/forge/card/abilityfactory/CommonDrawback.java svneol=native#text/plain
@@ -12478,6 +12476,7 @@ src/main/java/forge/card/abilityfactory/ai/AlwaysPlayAi.java -text
src/main/java/forge/card/abilityfactory/ai/AnimateAi.java -text
src/main/java/forge/card/abilityfactory/ai/AnimateAllAi.java -text
src/main/java/forge/card/abilityfactory/ai/BondAi.java -text
src/main/java/forge/card/abilityfactory/ai/CanPlayAsDrawbackAi.java -text
src/main/java/forge/card/abilityfactory/ai/CannotPlayAi.java -text
src/main/java/forge/card/abilityfactory/ai/ChooseCardAi.java -text
src/main/java/forge/card/abilityfactory/ai/ChooseCardNameAi.java -text
@@ -12487,6 +12486,7 @@ src/main/java/forge/card/abilityfactory/ai/ClashAi.java -text
src/main/java/forge/card/abilityfactory/ai/CloneAi.java -text
src/main/java/forge/card/abilityfactory/ai/ControlExchangeAi.java -text
src/main/java/forge/card/abilityfactory/ai/ControlGainAi.java -text
src/main/java/forge/card/abilityfactory/ai/CopyPermanentAi.java -text
src/main/java/forge/card/abilityfactory/ai/CounterAi.java -text
src/main/java/forge/card/abilityfactory/ai/CountersAi.java svneol=native#text/plain
src/main/java/forge/card/abilityfactory/ai/CountersMoveAi.java -text
@@ -12535,6 +12535,7 @@ src/main/java/forge/card/abilityfactory/ai/RearrangeTopOfLibraryAi.java -text
src/main/java/forge/card/abilityfactory/ai/RegenerateAi.java svneol=native#text/plain
src/main/java/forge/card/abilityfactory/ai/RegenerateAllAi.java -text
src/main/java/forge/card/abilityfactory/ai/RemoveFromCombatAi.java -text
src/main/java/forge/card/abilityfactory/ai/RepeatAi.java -text
src/main/java/forge/card/abilityfactory/ai/RevealAi.java -text
src/main/java/forge/card/abilityfactory/ai/RevealAiBase.java -text
src/main/java/forge/card/abilityfactory/ai/RevealHandAi.java -text
@@ -12568,6 +12569,8 @@ src/main/java/forge/card/abilityfactory/effects/ClashEffect.java -text
src/main/java/forge/card/abilityfactory/effects/CloneEffect.java -text
src/main/java/forge/card/abilityfactory/effects/ControlExchangeEffect.java -text
src/main/java/forge/card/abilityfactory/effects/ControlGainEffect.java -text
src/main/java/forge/card/abilityfactory/effects/CopyPermanentEffect.java -text
src/main/java/forge/card/abilityfactory/effects/CopySpellEffect.java -text
src/main/java/forge/card/abilityfactory/effects/CounterEffect.java -text
src/main/java/forge/card/abilityfactory/effects/CountersMoveEffect.java -text
src/main/java/forge/card/abilityfactory/effects/CountersProliferateEffect.java -text
@@ -12615,6 +12618,7 @@ src/main/java/forge/card/abilityfactory/effects/RearrangeTopOfLibraryEffect.java
src/main/java/forge/card/abilityfactory/effects/RegenerateAllEffect.java -text
src/main/java/forge/card/abilityfactory/effects/RegenerateEffect.java -text
src/main/java/forge/card/abilityfactory/effects/RemoveFromCombatEffect.java -text
src/main/java/forge/card/abilityfactory/effects/RepeatEffect.java -text
src/main/java/forge/card/abilityfactory/effects/RevealEffect.java -text
src/main/java/forge/card/abilityfactory/effects/RevealEffectBase.java svneol=native#text/plain
src/main/java/forge/card/abilityfactory/effects/RevealHandEffect.java -text

View File

@@ -507,30 +507,18 @@ public class AbilityFactory {
}
else if (this.api.equals("CopyPermanent")) {
if (this.isAb) {
spellAbility = AbilityFactoryCopy.createAbilityCopyPermanent(this);
} else if (this.isSp) {
spellAbility = AbilityFactoryCopy.createSpellCopyPermanent(this);
} else if (this.isDb) {
spellAbility = AbilityFactoryCopy.createDrawbackCopyPermanent(this);
}
ai = new CopyPermanentAi();
se = new CopyPermanentEffect();
}
else if (this.api.equals("CopySpell")) {
if (this.isTargeted) { // Since all "CopySpell" ABs copy things on
// the
// Stack no need for it to be everywhere
if (this.isTargeted) {
// Since all "CopySpell" ABs copy things on the Stack no need for it to be everywhere
this.abTgt.setZone(ZoneType.Stack);
}
if (this.isAb) {
spellAbility = AbilityFactoryCopy.createAbilityCopySpell(this);
} else if (this.isSp) {
spellAbility = AbilityFactoryCopy.createSpellCopySpell(this);
} else if (this.isDb) {
spellAbility = AbilityFactoryCopy.createDrawbackCopySpell(this);
}
ai = new CanPlayAsDrawbackAi();
se = new CopySpellEffect();
hostCard.setCopiesSpells(true);
}
@@ -810,13 +798,8 @@ public class AbilityFactory {
}
else if (this.api.equals("Repeat")) {
if (this.isAb) {
spellAbility = AbilityFactoryRepeat.createAbilityRepeat(this);
} else if (this.isSp) {
spellAbility = AbilityFactoryRepeat.createSpellRepeat(this);
} else if (this.isDb) {
spellAbility = AbilityFactoryRepeat.createDrawbackRepeat(this);
}
ai = new RepeatAi();
se = new RepeatEffect();
}
else if (this.api.equals("Reveal")) {

View File

@@ -1,850 +0,0 @@
/*
* 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.card.abilityfactory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import forge.Card;
import forge.CardCharacteristicName;
import forge.CardLists;
import forge.CardPredicates.Presets;
import forge.Command;
import forge.Singletons;
import forge.card.cost.Cost;
import forge.card.cardfactory.CardFactoryUtil;
import forge.card.spellability.Ability;
import forge.card.spellability.AbilityActivated;
import forge.card.spellability.AbilitySub;
import forge.card.spellability.Spell;
import forge.card.spellability.SpellAbility;
import forge.card.spellability.Target;
import forge.game.phase.PhaseType;
import forge.game.player.ComputerUtil;
import forge.game.player.Player;
import forge.game.zone.ZoneType;
import forge.gui.GuiChoose;
import forge.item.CardDb;
import forge.util.MyRandom;
/**
* <p>
* AbilityFactory_Copy class.
* </p>
*
* @author Forge
* @version $Id$
*/
public final class AbilityFactoryCopy {
private AbilityFactoryCopy() {
throw new AssertionError();
}
// *************************************************************************
// ************************* 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) {
class AbilityCopyPermanent extends AbilityActivated {
public AbilityCopyPermanent(final Card ca, final Cost co, final Target t) {
super(ca, co, t);
}
@Override
public AbilityActivated getCopy() {
AbilityActivated res = new AbilityCopyPermanent(getSourceCard(),
getPayCosts(), getTarget() == null ? null : new Target(getTarget()));
CardFactoryUtil.copySpellAbility(this, res);
return res;
}
private static final long serialVersionUID = 4557071554433108024L;
@Override
public String getStackDescription() {
return AbilityFactoryCopy.copyPermanentStackDescription(af, this);
}
@Override
public boolean canPlayAI() {
return AbilityFactoryCopy.copyPermanentCanPlayAI(getActivatingPlayer(), af, this);
}
@Override
public void resolve() {
AbilityFactoryCopy.copyPermanentResolve(af, this);
}
@Override
public boolean doTrigger(final boolean mandatory) {
return AbilityFactoryCopy.copyPermanentTriggerAI(getActivatingPlayer(), af, this, mandatory);
}
}
final SpellAbility abCopyPermanent = new AbilityCopyPermanent(af.getHostCard(), af.getAbCost(), af.getAbTgt());
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 AbilityFactoryCopy.copyPermanentStackDescription(af, this);
}
@Override
public boolean canPlayAI() {
return AbilityFactoryCopy.copyPermanentCanPlayAI(getActivatingPlayer(), af, this);
}
@Override
public void resolve() {
AbilityFactoryCopy.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) {
class DrawbackCopyPermanent extends AbilitySub {
public DrawbackCopyPermanent(final Card ca, final Target t) {
super(ca, t);
}
@Override
public AbilitySub getCopy() {
AbilitySub res = new DrawbackCopyPermanent(getSourceCard(),
getTarget() == null ? null : new Target(getTarget()));
CardFactoryUtil.copySpellAbility(this, res);
return res;
}
private static final long serialVersionUID = -7725564505830285184L;
@Override
public String getStackDescription() {
return AbilityFactoryCopy.copyPermanentStackDescription(af, this);
}
@Override
public void resolve() {
AbilityFactoryCopy.copyPermanentResolve(af, this);
}
@Override
public boolean chkAIDrawback() {
return true;
}
@Override
public boolean doTrigger(final boolean mandatory) {
return AbilityFactoryCopy.copyPermanentTriggerAI(getActivatingPlayer(), af, this, mandatory);
}
}
final SpellAbility dbCopyPermanent = new DrawbackCopyPermanent(af.getHostCard(), af.getAbTgt());
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(final AbilityFactory af, final SpellAbility sa) {
final StringBuilder sb = new StringBuilder();
final HashMap<String, String> params = af.getMapParams();
if (!(sa instanceof AbilitySub)) {
sb.append(sa.getSourceCard()).append(" - ");
} else {
sb.append(" ");
}
ArrayList<Card> tgtCards;
final Target tgt = sa.getTarget();
if (tgt != null) {
tgtCards = tgt.getTargetCards();
} else {
tgtCards = AbilityFactory.getDefinedCards(sa.getSourceCard(), params.get("Defined"), sa);
}
sb.append("Copy ");
final Iterator<Card> it = tgtCards.iterator();
while (it.hasNext()) {
sb.append(it.next());
if (it.hasNext()) {
sb.append(", ");
}
}
sb.append(".");
final AbilitySub 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 Player ai, final AbilityFactory af, final SpellAbility sa) {
// Card source = sa.getSourceCard();
// TODO - I'm sure someone can do this AI better
final HashMap<String, String> params = af.getMapParams();
if (params.containsKey("AtEOT") && !Singletons.getModel().getGame().getPhaseHandler().is(PhaseType.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)
}
final Random r = MyRandom.getRandom();
if (r.nextFloat() <= Math.pow(chance, sa.getActivationsThisTurn() + 1)) {
return AbilityFactoryCopy.copyPermanentTriggerAI(ai, 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 Player ai, final AbilityFactory af, final SpellAbility sa,
final boolean mandatory) {
// HashMap<String,String> params = af.getMapParams();
final Card source = sa.getSourceCard();
if (!ComputerUtil.canPayCost(sa, ai) && !mandatory) {
return false;
}
// ////
// Targeting
final Target abTgt = sa.getTarget();
if (abTgt != null) {
List<Card> list = Singletons.getModel().getGame().getCardsIn(ZoneType.Battlefield);
list = CardLists.getValidCards(list, abTgt.getValidTgts(), source.getController(), source);
list = CardLists.getTargetableCards(list, sa);
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 (CardLists.filter(list, Presets.CREATURES).size() > 0) {
choice = CardFactoryUtil.getBestCreatureAI(list);
} else {
choice = CardFactoryUtil.getMostExpensivePermanentAI(list, sa, 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
final AbilitySub abSub = sa.getSubAbility();
if (abSub != null) {
return abSub.chkAIDrawback();
}
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();
final Card hostCard = sa.getSourceCard();
final ArrayList<String> keywords = new ArrayList<String>();
if (params.containsKey("Keywords")) {
keywords.addAll(Arrays.asList(params.get("Keywords").split(" & ")));
}
final int numCopies = params.containsKey("NumCopies") ? AbilityFactory.calculateAmount(hostCard,
params.get("NumCopies"), sa) : 1;
ArrayList<Card> tgtCards;
final Target tgt = sa.getTarget();
if (tgt != null) {
tgtCards = tgt.getTargetCards();
} else {
tgtCards = AbilityFactory.getDefinedCards(sa.getSourceCard(), params.get("Defined"), sa);
}
hostCard.clearClones();
for (final Card c : tgtCards) {
if ((tgt == null) || c.canBeTargetedBy(sa)) {
boolean wasInAlt = false;
CardCharacteristicName stateName = CardCharacteristicName.Original;
if (c.isInAlternateState()) {
stateName = c.getCurState();
wasInAlt = true;
c.setState(CardCharacteristicName.Original);
}
// start copied Kiki code
int multiplier = hostCard.getController().getTokenDoublersMagnitude();
multiplier *= numCopies;
final Card[] crds = new Card[multiplier];
for (int i = 0; i < multiplier; i++) {
// TODO Use central copy methods
Card copy;
if (!c.isToken() || c.isCopiedToken()) {
// copy creature and put it onto the battlefield
copy = Singletons.getModel().getCardFactory().getCard(CardDb.instance().getCard(c), sa.getActivatingPlayer());
// when copying something stolen:
copy.addController(sa.getActivatingPlayer());
copy.setToken(true);
copy.setCopiedToken(true);
} else { // isToken()
copy = CardFactoryUtil.copyStats(c);
copy.setName(c.getName());
copy.setImageName(c.getImageName());
copy.setOwner(sa.getActivatingPlayer());
copy.addController(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 (final String kw : keywords) {
copy.addIntrinsicKeyword(kw);
}
copy.setCurSetCode(c.getCurSetCode());
if (c.isDoubleFaced()) { // Cloned DFC's can't transform
if (wasInAlt) {
copy.setState(CardCharacteristicName.Transformed);
}
}
if (c.isFlipCard()) { // Cloned Flips CAN flip.
copy.setState(CardCharacteristicName.Original);
c.setState(CardCharacteristicName.Original);
copy.setImageFilename(c.getImageFilename());
if (!c.isInAlternateState()) {
copy.setState(CardCharacteristicName.Flipped);
}
c.setState(CardCharacteristicName.Flipped);
}
if (c.isFaceDown()) {
c.setState(CardCharacteristicName.FaceDown);
}
copy = Singletons.getModel().getGame().getAction().moveToPlay(copy);
copy.setCloneOrigin(hostCard);
sa.getSourceCard().addClone(copy);
crds[i] = copy;
}
if (wasInAlt) {
c.setState(stateName);
}
// 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 (target[index].isInPlay()) {
if (params.get("AtEOT").equals("Sacrifice")) {
// maybe do a setSacrificeAtEOT, but
// probably not.
Singletons.getModel().getGame().getAction().sacrifice(target[index], sa);
} else if (params.get("AtEOT").equals("Exile")) {
Singletons.getModel().getGame().getAction().exile(target[index]);
}
}
}
};
final Command atEOT = new Command() {
private static final long serialVersionUID = -4184510100801568140L;
@Override
public void execute() {
sac.setStackDescription(params.get("AtEOT") + " " + target[index] + ".");
Singletons.getModel().getGame().getStack().addSimultaneousStackEntry(sac);
}
}; // Command
if (params.containsKey("AtEOT")) {
Singletons.getModel().getGame().getEndOfTurn().addAt(atEOT);
}
// end copied Kiki code
}
} // end canBeTargetedBy
} // 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) {
class AbilityCopySpell extends AbilityActivated {
public AbilityCopySpell(final Card ca, final Cost co, final Target t) {
super(ca, co, t);
}
@Override
public AbilityActivated getCopy() {
AbilityActivated res = new AbilityCopySpell(getSourceCard(),
getPayCosts(), getTarget() == null ? null : new Target(getTarget()));
CardFactoryUtil.copySpellAbility(this, res);
return res;
}
private static final long serialVersionUID = 5232548517225345052L;
@Override
public String getStackDescription() {
return AbilityFactoryCopy.copySpellStackDescription(af, this);
}
@Override
public boolean canPlayAI() {
return AbilityFactoryCopy.copySpellCanPlayAI(af, this);
}
@Override
public void resolve() {
AbilityFactoryCopy.copySpellResolve(af, this);
}
@Override
public boolean doTrigger(final boolean mandatory) {
return AbilityFactoryCopy.copySpellTriggerAI(af, this, mandatory);
}
}
final SpellAbility abCopySpell = new AbilityCopySpell(af.getHostCard(), af.getAbCost(), af.getAbTgt());
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 AbilityFactoryCopy.copySpellStackDescription(af, this);
}
@Override
public boolean canPlayAI() {
return AbilityFactoryCopy.copySpellCanPlayAI(af, this);
}
@Override
public void resolve() {
AbilityFactoryCopy.copySpellResolve(af, this);
}
@Override
public boolean canPlayFromEffectAI(final boolean mandatory, final boolean withOutManaCost) {
if (withOutManaCost) {
return true;
}
return AbilityFactoryCopy.copySpellTriggerAI(af, this, mandatory);
}
};
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) {
class DrawbackCopySpell extends AbilitySub {
public DrawbackCopySpell(final Card ca, final Target t) {
super(ca, t);
}
@Override
public AbilitySub getCopy() {
AbilitySub res = new DrawbackCopySpell(getSourceCard(),
getTarget() == null ? null : new Target(getTarget()));
CardFactoryUtil.copySpellAbility(this, res);
return res;
}
private static final long serialVersionUID = 1927508119173644632L;
@Override
public String getStackDescription() {
return AbilityFactoryCopy.copySpellStackDescription(af, this);
}
@Override
public void resolve() {
AbilityFactoryCopy.copySpellResolve(af, this);
}
@Override
public boolean chkAIDrawback() {
return true;
}
@Override
public boolean doTrigger(final boolean mandatory) {
return AbilityFactoryCopy.copySpellTriggerAI(af, this, mandatory);
}
}
final SpellAbility dbCopySpell = new DrawbackCopySpell(af.getHostCard(), af.getAbTgt());
return dbCopySpell;
}
/**
* <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, final boolean mandatory) {
final boolean randomReturn = false;
// comment out the af.hasSubAbility() until it's used. randomReturn is
// always false.
/*
* if (af.hasSubAbility()) { final AbilitySub abSub =
* sa.getSubAbility(); if (abSub != null) { return randomReturn &&
* abSub.chkAIDrawback(); } }
*/
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();
final Card card = sa.getSourceCard();
Player controller = sa.getActivatingPlayer();
int amount = 1;
if (params.containsKey("Amount")) {
amount = AbilityFactory.calculateAmount(card, params.get("Amount"), sa);
}
if (params.containsKey("Controller")) {
controller = AbilityFactory.getDefinedPlayers(card, params.get("Controller"), sa).get(0);
}
ArrayList<SpellAbility> tgtSpells;
final Target tgt = sa.getTarget();
if (tgt != null) {
tgtSpells = tgt.getTargetSAs();
} else {
tgtSpells = AbilityFactory.getDefinedSpellAbilities(sa.getSourceCard(), params.get("Defined"), sa);
}
if (tgtSpells.size() == 0) {
return;
}
if (params.containsKey("CopyMultipleSpells")) {
final int spellCount = Integer.parseInt(params.get("CopyMultipleSpells"));
ArrayList<SpellAbility> chosenSAs = new ArrayList<SpellAbility>();
SpellAbility chosenSAtmp = null;
for (int multi = 0; multi < spellCount; multi++) {
if (tgtSpells.size() == 1) {
chosenSAs.addAll(tgtSpells);
} else if (sa.getActivatingPlayer().isHuman()) {
String num = "";
if (multi == 1 - 1) {
num = "first";
}
else if (multi == 2 - 1) {
num = "second";
}
else if (multi == 3 - 1) {
num = "third";
} else {
num = Integer.toString(multi - 1) + "th";
}
chosenSAtmp = GuiChoose.one("Select " + num + " spell to copy to stack", tgtSpells);
chosenSAs.add(chosenSAtmp);
tgtSpells.remove(chosenSAtmp);
} else {
chosenSAs.add(tgtSpells.get(multi));
}
}
for (final SpellAbility chosenSAcopy : chosenSAs) {
chosenSAcopy.setActivatingPlayer(controller);
for (int i = 0; i < amount; i++) {
Singletons.getModel().getCardFactory().copySpellontoStack(card, chosenSAcopy.getSourceCard(), chosenSAcopy, true);
}
}
}
else {
SpellAbility chosenSA = null;
if (tgtSpells.size() == 1) {
chosenSA = tgtSpells.get(0);
} else if (sa.getActivatingPlayer().isHuman()) {
chosenSA = GuiChoose.one("Select a spell to copy", tgtSpells);
} else {
chosenSA = tgtSpells.get(0);
}
chosenSA.setActivatingPlayer(controller);
for (int i = 0; i < amount; i++) {
Singletons.getModel().getCardFactory().copySpellontoStack(card, chosenSA.getSourceCard(), chosenSA, true);
}
}
} // end resolve
/**
* <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(final AbilityFactory af, final SpellAbility sa) {
final StringBuilder sb = new StringBuilder();
final HashMap<String, String> params = af.getMapParams();
if (!(sa instanceof AbilitySub)) {
sb.append(sa.getSourceCard().getName()).append(" - ");
} else {
sb.append(" ");
}
ArrayList<SpellAbility> tgtSpells;
final Target tgt = sa.getTarget();
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
final Iterator<SpellAbility> it = tgtSpells.iterator();
while (it.hasNext()) {
sb.append(it.next().getSourceCard());
if (it.hasNext()) {
sb.append(", ");
}
}
int amount = 1;
if (params.containsKey("Amount")) {
amount = AbilityFactory.calculateAmount(sa.getSourceCard(), params.get("Amount"), sa);
}
if (amount > 1) {
sb.append(amount).append(" times");
}
sb.append(".");
// TODO probably add an optional "You may choose new targets..."
final AbilitySub abSub = sa.getSubAbility();
if (abSub != null) {
sb.append(abSub.getStackDescription());
}
return sb.toString();
}
} // end class AbilityFactory_Copy

View File

@@ -1,369 +0,0 @@
/*
* 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.card.abilityfactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import forge.Card;
import forge.CardLists;
import forge.Singletons;
import forge.card.cost.Cost;
import forge.GameActionUtil;
import forge.card.cardfactory.CardFactoryUtil;
import forge.card.spellability.AbilityActivated;
import forge.card.spellability.AbilitySub;
import forge.card.spellability.Spell;
import forge.card.spellability.SpellAbility;
import forge.card.spellability.Target;
import forge.game.player.Player;
import forge.game.zone.ZoneType;
import forge.util.Expressions;
/**
* <p>
* AbilityFactory_Repeat class.
* </p>
*
* @author Forge
* @version $Id: AbilityFactoryRepeat.java 15090 2012-04-07 12:50:31Z Max mtg $
*/
public final class AbilityFactoryRepeat {
private AbilityFactoryRepeat() {
throw new AssertionError();
}
/**
* <p>
* getAbilityRepeat.
* </p>
*
* @param af
* a {@link forge.card.abilityfactory.AbilityFactory} object.
* @return a {@link forge.card.spellability.SpellAbility} object.
* @since 1.0.15
*/
public static SpellAbility createAbilityRepeat(final AbilityFactory af) {
class AbilityRepeat extends AbilityActivated {
public AbilityRepeat(final Card ca, final Cost co, final Target t) {
super(ca, co, t);
}
@Override
public AbilityActivated getCopy() {
AbilityActivated res = new AbilityRepeat(getSourceCard(),
getPayCosts(), getTarget() == null ? null : new Target(getTarget()));
CardFactoryUtil.copySpellAbility(this, res);
return res;
}
private static final long serialVersionUID = -8019637116128196482L;
@Override
public boolean canPlayAI() {
return AbilityFactoryRepeat.repeatCanPlayAI(getActivatingPlayer(), this);
}
@Override
public boolean doTrigger(final boolean mandatory) {
return AbilityFactoryRepeat.repeatCanPlayAI(getActivatingPlayer(), this) || mandatory;
}
@Override
public String getStackDescription() {
return AbilityFactoryRepeat.repeatStackDescription(af, this);
}
@Override
public void resolve() {
AbilityFactoryRepeat.repeatResolve(af, this);
}
}
final SpellAbility abRepeat = new AbilityRepeat(af.getHostCard(), af.getAbCost(), af.getAbTgt());
return abRepeat;
}
/**
* <p>
* createSpellRepeat.
* </p>
*
* @param af
* a {@link forge.card.abilityfactory.AbilityFactory} object.
* @return a {@link forge.card.spellability.SpellAbility} object.
* @since 1.0.15
*/
public static SpellAbility createSpellRepeat(final AbilityFactory af) {
final SpellAbility spRepeat = new Spell(af.getHostCard(), af.getAbCost(), af.getAbTgt()) {
private static final long serialVersionUID = -4991665176268317217L;
@Override
public boolean canPlayAI() {
return AbilityFactoryRepeat.repeatCanPlayAI(getActivatingPlayer(), this);
}
@Override
public boolean doTrigger(final boolean mandatory) {
return AbilityFactoryRepeat.repeatCanPlayAI(getActivatingPlayer(), this) || mandatory;
}
@Override
public String getStackDescription() {
return AbilityFactoryRepeat.repeatStackDescription(af, this);
}
@Override
public void resolve() {
AbilityFactoryRepeat.repeatResolve(af, this);
}
};
return spRepeat;
}
/**
* <p>
* createDrawbackRepeat.
* </p>
*
* @param af
* a {@link forge.card.abilityfactory.AbilityFactory} object.
* @return a {@link forge.card.spellability.SpellAbility} object.
* @since 1.0.15
*/
public static SpellAbility createDrawbackRepeat(final AbilityFactory af) {
class DrawbackRepeat extends AbilitySub {
public DrawbackRepeat(final Card ca, final Target t) {
super(ca, t);
}
@Override
public AbilitySub getCopy() {
AbilitySub res = new DrawbackRepeat(getSourceCard(), new Target(getTarget()));
CardFactoryUtil.copySpellAbility(this, res);
return res;
}
private static final long serialVersionUID = -3850086157052881036L;
@Override
public boolean canPlayAI() {
return true;
}
@Override
public boolean chkAIDrawback() {
return true;
}
@Override
public boolean doTrigger(final boolean mandatory) {
return AbilityFactoryRepeat.repeatCanPlayAI(getActivatingPlayer(), this) || mandatory;
}
@Override
public String getStackDescription() {
return AbilityFactoryRepeat.repeatStackDescription(af, this);
}
@Override
public void resolve() {
AbilityFactoryRepeat.repeatResolve(af, this);
}
}
final SpellAbility dbRepeat = new DrawbackRepeat(af.getHostCard(), af.getAbTgt());
return dbRepeat;
}
private static boolean repeatCanPlayAI(final Player ai, final SpellAbility sa) {
final Target tgt = sa.getTarget();
final Player opp = ai.getOpponent();
if (tgt != null) {
if (!opp.canBeTargetedBy(sa)) {
return false;
}
tgt.resetTargets();
tgt.addTarget(opp);
}
return true;
}
/**
* <p>
* repeatResolve.
* </p>
*
* @param AF
* a {@link forge.card.abilityfactory.AbilityFactory} object.
* @param SA
* a {@link forge.card.spellability.SpellAbility} object.
*/
private static void repeatResolve(final AbilityFactory af, final SpellAbility sa) {
final AbilityFactory afRepeat = new AbilityFactory();
final HashMap<String, String> params = af.getMapParams();
Card source = sa.getSourceCard();
// setup subability to repeat
final SpellAbility repeat = afRepeat.getAbility(
af.getHostCard().getSVar(params.get("RepeatSubAbility")), source);
repeat.setActivatingPlayer(sa.getActivatingPlayer());
((AbilitySub) repeat).setParent(sa);
Integer maxRepeat = null;
if (params.containsKey("MaxRepeat")) {
maxRepeat = AbilityFactory.calculateAmount(sa.getSourceCard(), params.get("MaxRepeat"), sa);
}
//execute repeat ability at least once
int count = 0;
do {
AbilityFactory.resolve(repeat, false);
count++;
if (maxRepeat != null && maxRepeat <= count) {
// TODO Replace Infinite Loop Break with a game draw. Here are the scenarios that can cause this:
// Helm of Obedience vs Graveyard to Library replacement effect
StringBuilder infLoop = new StringBuilder(sa.getSourceCard().toString());
infLoop.append(" - To avoid an infinite loop, this repeat has been broken ");
infLoop.append(" and the game will now continue in the current state, ending the loop early. ");
infLoop.append("Once Draws are available this probably should change to a Draw.");
System.out.println(infLoop.toString());
break;
}
} while (checkRepeatConditions(af, sa));
}
/**
* <p>
* checkRepeatConditions.
* </p>
*
* @param AF
* a {@link forge.card.abilityfactory.AbilityFactory} object.
* @param SA
* a {@link forge.card.spellability.SpellAbility} object.
*/
private static boolean checkRepeatConditions(final AbilityFactory af, final SpellAbility sa) {
//boolean doAgain = false;
final HashMap<String, String> params = af.getMapParams();
if (params.containsKey("RepeatPresent")) {
final String repeatPresent = params.get("RepeatPresent");
List<Card> list = new ArrayList<Card>();
String repeatCompare = "GE1";
if (params.containsKey("RepeatCompare")) {
repeatCompare = params.get("RepeatCompare");
}
if (params.containsKey("RepeatDefined")) {
list.addAll(AbilityFactory.getDefinedCards(sa.getSourceCard(), params.get("RepeatDefined"), sa));
} else {
list = Singletons.getModel().getGame().getCardsIn(ZoneType.Battlefield);
}
list = CardLists.getValidCards(list, repeatPresent.split(","), sa.getActivatingPlayer(), sa.getSourceCard());
int right;
final String rightString = repeatCompare.substring(2);
try { // If this is an Integer, just parse it
right = Integer.parseInt(rightString);
} catch (final NumberFormatException e) { // Otherwise, grab it from
// the
// SVar
right = CardFactoryUtil.xCount(sa.getSourceCard(), sa.getSourceCard().getSVar(rightString));
}
final int left = list.size();
if (!Expressions.compare(left, repeatCompare, right)) {
return false;
}
}
if (params.containsKey("RepeatCheckSVar")) {
String sVarOperator = "GE";
String sVarOperand = "1";
if (params.containsKey("RepeatSVarCompare")) {
sVarOperator = params.get("RepeatSVarCompare").substring(0, 2);
sVarOperand = params.get("RepeatSVarCompare").substring(2);
}
final int svarValue = AbilityFactory.calculateAmount(sa.getSourceCard(), params.get("RepeatCheckSVar"), sa);
final int operandValue = AbilityFactory.calculateAmount(sa.getSourceCard(), sVarOperand, sa);
if (!Expressions.compare(svarValue, sVarOperator, operandValue)) {
return false;
}
}
if (params.containsKey("RepeatOptional")) {
if (sa.getActivatingPlayer().isComputer()) {
//TODO add logic to have computer make better choice (ArsenalNut)
return false;
} else {
final StringBuilder sb = new StringBuilder();
sb.append("Do you want to repeat this process again?");
if (!GameActionUtil.showYesNoDialog(sa.getSourceCard(), sb.toString())) {
return false;
}
}
}
return true;
}
/**
* <p>
* repeatStackDescription.
* </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 repeatStackDescription(final AbilityFactory af, final SpellAbility sa) {
final HashMap<String, String> params = af.getMapParams();
final StringBuilder sb = new StringBuilder();
final Card host = sa.getSourceCard();
if (!(sa instanceof AbilitySub)) {
sb.append(host.getName()).append(" -");
}
sb.append(" ");
if (params.containsKey("StackDescription")) {
final String desc = params.get("StackDescription");
if (!desc.equals("None")) {
sb.append(params.get("StackDescription"));
}
} else {
sb.append("Repeat something. Somebody should really write a better StackDescription!");
}
return sb.toString();
} // end repeatStackDescription()
} // end class AbilityFactory_Repeat

View File

@@ -0,0 +1,65 @@
package forge.card.abilityfactory.ai;
import java.util.Map;
import forge.card.abilityfactory.SpellAiLogic;
import forge.card.spellability.SpellAbility;
import forge.game.player.Player;
public class CanPlayAsDrawbackAi extends SpellAiLogic {
/* (non-Javadoc)
* @see forge.card.abilityfactory.SpellAiLogic#canPlayAI(forge.game.player.Player, java.util.Map, forge.card.spellability.SpellAbility)
*/
@Override
public boolean canPlayAI(Player aiPlayer, Map<String, String> params, SpellAbility sa) {
return false;
}
/* (non-Javadoc)
* @see forge.card.abilityfactory.SpellAiLogic#chkAIDrawback(java.util.Map, forge.card.spellability.SpellAbility, forge.game.player.Player)
*/
@Override
public boolean chkAIDrawback(Map<String, String> params, SpellAbility sa, Player aiPlayer) {
return true;
}
/**
* <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.
*/
@Override
public boolean doTriggerAINoCost(Player aiPlayer, java.util.Map<String,String> params, SpellAbility sa, boolean mandatory) {
final boolean randomReturn = false;
// comment out the af.hasSubAbility() until it's used. randomReturn is
// always false.
/*
* if (af.hasSubAbility()) { final AbilitySub abSub =
* sa.getSubAbility(); if (abSub != null) { return randomReturn &&
* abSub.chkAIDrawback(); } }
*/
return randomReturn;
}
/**
* <p>
* copySpellResolve.
* </p>
*
* @param af
* a {@link forge.card.abilityfactory.AbilityFactory} object.
* @param sa
* a {@link forge.card.spellability.SpellAbility} object.
*/
}

View File

@@ -0,0 +1,141 @@
package forge.card.abilityfactory.ai;
import java.util.List;
import java.util.Map;
import java.util.Random;
import forge.Card;
import forge.CardLists;
import forge.Singletons;
import forge.CardPredicates.Presets;
import forge.card.abilityfactory.AbilityFactory;
import forge.card.abilityfactory.SpellAiLogic;
import forge.card.cardfactory.CardFactoryUtil;
import forge.card.spellability.AbilitySub;
import forge.card.spellability.SpellAbility;
import forge.card.spellability.Target;
import forge.game.phase.PhaseType;
import forge.game.player.Player;
import forge.game.zone.ZoneType;
import forge.util.MyRandom;
public class CopyPermanentAi extends SpellAiLogic {
/* (non-Javadoc)
* @see forge.card.abilityfactory.SpellAiLogic#canPlayAI(forge.game.player.Player, java.util.Map, forge.card.spellability.SpellAbility)
*/
@Override
public boolean canPlayAI(Player aiPlayer, Map<String, String> params, SpellAbility sa) {
// Card source = sa.getSourceCard();
// TODO - I'm sure someone can do this AI better
if (params.containsKey("AtEOT") && !Singletons.getModel().getGame().getPhaseHandler().is(PhaseType.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)
}
final Random r = MyRandom.getRandom();
if (r.nextFloat() <= Math.pow(chance, sa.getActivationsThisTurn() + 1)) {
return this.doTriggerAINoCost(aiPlayer, params, sa, false);
} else {
return false;
}
}
}
@Override
public boolean chkAIDrawback(java.util.Map<String,String> params, SpellAbility sa, Player aiPlayer) {
return true;
}
/**
* <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.
*/
@Override
public boolean doTriggerAINoCost(Player aiPlayer, java.util.Map<String,String> params, SpellAbility sa, boolean mandatory) {
final Card source = sa.getSourceCard();
// ////
// Targeting
final Target abTgt = sa.getTarget();
if (abTgt != null) {
List<Card> list = Singletons.getModel().getGame().getCardsIn(ZoneType.Battlefield);
list = CardLists.getValidCards(list, abTgt.getValidTgts(), source.getController(), source);
list = CardLists.getTargetableCards(list, sa);
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 (CardLists.filter(list, Presets.CREATURES).size() > 0) {
choice = CardFactoryUtil.getBestCreatureAI(list);
} else {
choice = CardFactoryUtil.getMostExpensivePermanentAI(list, sa, 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
final AbilitySub abSub = sa.getSubAbility();
if (abSub != null) {
return abSub.chkAIDrawback();
}
return true;
}
/**
* <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.
*/
}

View File

@@ -0,0 +1,43 @@
package forge.card.abilityfactory.ai;
import java.util.Map;
import forge.card.abilityfactory.SpellAiLogic;
import forge.card.spellability.SpellAbility;
import forge.card.spellability.Target;
import forge.game.player.Player;
public class RepeatAi extends SpellAiLogic {
/* (non-Javadoc)
* @see forge.card.abilityfactory.SpellAiLogic#doTriggerAI(forge.game.player.Player, java.util.Map, forge.card.spellability.SpellAbility, boolean)
*/
@Override
public boolean doTriggerAI(Player aiPlayer, Map<String, String> params, SpellAbility sa, boolean mandatory) {
return canPlayAI(aiPlayer, params, sa) || mandatory;
}
@Override
public boolean canPlayAI(Player ai, java.util.Map<String,String> params, SpellAbility sa) {
final Target tgt = sa.getTarget();
final Player opp = ai.getOpponent();
if (tgt != null) {
if (!opp.canBeTargetedBy(sa)) {
return false;
}
tgt.resetTargets();
tgt.addTarget(opp);
}
return true;
}
/* (non-Javadoc)
* @see forge.card.abilityfactory.SpellAiLogic#chkAIDrawback(java.util.Map, forge.card.spellability.SpellAbility, forge.game.player.Player)
*/
@Override
public boolean chkAIDrawback(Map<String, String> params, SpellAbility sa, Player aiPlayer) {
return true;
}
}

View File

@@ -0,0 +1,232 @@
package forge.card.abilityfactory.effects;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import forge.Card;
import forge.CardCharacteristicName;
import forge.Command;
import forge.Singletons;
import forge.card.abilityfactory.AbilityFactory;
import forge.card.abilityfactory.SpellEffect;
import forge.card.cardfactory.CardFactoryUtil;
import forge.card.spellability.Ability;
import forge.card.spellability.AbilitySub;
import forge.card.spellability.SpellAbility;
import forge.card.spellability.Target;
import forge.item.CardDb;
public class CopyPermanentEffect extends SpellEffect {
@Override
protected String getStackDescription(java.util.Map<String,String> params, SpellAbility sa) {
final StringBuilder sb = new StringBuilder();
if (!(sa instanceof AbilitySub)) {
sb.append(sa.getSourceCard()).append(" - ");
} else {
sb.append(" ");
}
ArrayList<Card> tgtCards;
final Target tgt = sa.getTarget();
if (tgt != null) {
tgtCards = tgt.getTargetCards();
} else {
tgtCards = AbilityFactory.getDefinedCards(sa.getSourceCard(), params.get("Defined"), sa);
}
sb.append("Copy ");
final Iterator<Card> it = tgtCards.iterator();
while (it.hasNext()) {
sb.append(it.next());
if (it.hasNext()) {
sb.append(", ");
}
}
sb.append(".");
return sb.toString();
}
/**
* <p>
* copyPermanentResolve.
* </p>
*
* @param af
* a {@link forge.card.abilityfactory.AbilityFactory} object.
* @param sa
* a {@link forge.card.spellability.SpellAbility} object.
*/
@Override
public void resolve(final java.util.Map<String,String> params, final SpellAbility sa) {
final Card hostCard = sa.getSourceCard();
final ArrayList<String> keywords = new ArrayList<String>();
if (params.containsKey("Keywords")) {
keywords.addAll(Arrays.asList(params.get("Keywords").split(" & ")));
}
final int numCopies = params.containsKey("NumCopies") ? AbilityFactory.calculateAmount(hostCard,
params.get("NumCopies"), sa) : 1;
ArrayList<Card> tgtCards;
final Target tgt = sa.getTarget();
if (tgt != null) {
tgtCards = tgt.getTargetCards();
} else {
tgtCards = AbilityFactory.getDefinedCards(sa.getSourceCard(), params.get("Defined"), sa);
}
hostCard.clearClones();
for (final Card c : tgtCards) {
if ((tgt == null) || c.canBeTargetedBy(sa)) {
boolean wasInAlt = false;
CardCharacteristicName stateName = CardCharacteristicName.Original;
if (c.isInAlternateState()) {
stateName = c.getCurState();
wasInAlt = true;
c.setState(CardCharacteristicName.Original);
}
// start copied Kiki code
int multiplier = hostCard.getController().getTokenDoublersMagnitude();
multiplier *= numCopies;
final Card[] crds = new Card[multiplier];
for (int i = 0; i < multiplier; i++) {
// TODO Use central copy methods
Card copy;
if (!c.isToken() || c.isCopiedToken()) {
// copy creature and put it onto the battlefield
copy = Singletons.getModel().getCardFactory().getCard(CardDb.instance().getCard(c), sa.getActivatingPlayer());
// when copying something stolen:
copy.addController(sa.getActivatingPlayer());
copy.setToken(true);
copy.setCopiedToken(true);
} else { // isToken()
copy = CardFactoryUtil.copyStats(c);
copy.setName(c.getName());
copy.setImageName(c.getImageName());
copy.setOwner(sa.getActivatingPlayer());
copy.addController(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 (final String kw : keywords) {
copy.addIntrinsicKeyword(kw);
}
copy.setCurSetCode(c.getCurSetCode());
if (c.isDoubleFaced()) { // Cloned DFC's can't transform
if (wasInAlt) {
copy.setState(CardCharacteristicName.Transformed);
}
}
if (c.isFlipCard()) { // Cloned Flips CAN flip.
copy.setState(CardCharacteristicName.Original);
c.setState(CardCharacteristicName.Original);
copy.setImageFilename(c.getImageFilename());
if (!c.isInAlternateState()) {
copy.setState(CardCharacteristicName.Flipped);
}
c.setState(CardCharacteristicName.Flipped);
}
if (c.isFaceDown()) {
c.setState(CardCharacteristicName.FaceDown);
}
copy = Singletons.getModel().getGame().getAction().moveToPlay(copy);
copy.setCloneOrigin(hostCard);
sa.getSourceCard().addClone(copy);
crds[i] = copy;
}
if (wasInAlt) {
c.setState(stateName);
}
// 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 (target[index].isInPlay()) {
if (params.get("AtEOT").equals("Sacrifice")) {
// maybe do a setSacrificeAtEOT, but
// probably not.
Singletons.getModel().getGame().getAction().sacrifice(target[index], sa);
} else if (params.get("AtEOT").equals("Exile")) {
Singletons.getModel().getGame().getAction().exile(target[index]);
}
}
}
};
final Command atEOT = new Command() {
private static final long serialVersionUID = -4184510100801568140L;
@Override
public void execute() {
sac.setStackDescription(params.get("AtEOT") + " " + target[index] + ".");
Singletons.getModel().getGame().getStack().addSimultaneousStackEntry(sac);
}
}; // Command
if (params.containsKey("AtEOT")) {
Singletons.getModel().getGame().getEndOfTurn().addAt(atEOT);
}
// end copied Kiki code
}
} // end canBeTargetedBy
} // end foreach Card
} // end resolve
// *************************************************************************
// ************************* CopySpell *************************************
// *************************************************************************
/**
* <p>
* copySpellCanPlayAI.
* </p>
*
* @param af
* a {@link forge.card.abilityfactory.AbilityFactory} object.
* @param sa
* a {@link forge.card.spellability.SpellAbility} object.
* @return a boolean.
*/
}

View File

@@ -0,0 +1,152 @@
package forge.card.abilityfactory.effects;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import forge.Card;
import forge.Singletons;
import forge.card.abilityfactory.AbilityFactory;
import forge.card.abilityfactory.SpellEffect;
import forge.card.spellability.AbilitySub;
import forge.card.spellability.SpellAbility;
import forge.card.spellability.Target;
import forge.game.player.Player;
import forge.gui.GuiChoose;
public class CopySpellEffect extends SpellEffect {
/* (non-Javadoc)
* @see forge.card.abilityfactory.SpellEffect#resolve(java.util.Map, forge.card.spellability.SpellAbility)
*/
@Override
public void resolve(Map<String, String> params, SpellAbility sa) {
final Card card = sa.getSourceCard();
Player controller = sa.getActivatingPlayer();
int amount = 1;
if (params.containsKey("Amount")) {
amount = AbilityFactory.calculateAmount(card, params.get("Amount"), sa);
}
if (params.containsKey("Controller")) {
controller = AbilityFactory.getDefinedPlayers(card, params.get("Controller"), sa).get(0);
}
ArrayList<SpellAbility> tgtSpells;
final Target tgt = sa.getTarget();
if (tgt != null) {
tgtSpells = tgt.getTargetSAs();
} else {
tgtSpells = AbilityFactory.getDefinedSpellAbilities(sa.getSourceCard(), params.get("Defined"), sa);
}
if (tgtSpells.size() == 0) {
return;
}
if (params.containsKey("CopyMultipleSpells")) {
final int spellCount = Integer.parseInt(params.get("CopyMultipleSpells"));
ArrayList<SpellAbility> chosenSAs = new ArrayList<SpellAbility>();
SpellAbility chosenSAtmp = null;
for (int multi = 0; multi < spellCount; multi++) {
if (tgtSpells.size() == 1) {
chosenSAs.addAll(tgtSpells);
} else if (sa.getActivatingPlayer().isHuman()) {
String num = "";
if (multi == 1 - 1) {
num = "first";
}
else if (multi == 2 - 1) {
num = "second";
}
else if (multi == 3 - 1) {
num = "third";
} else {
num = Integer.toString(multi - 1) + "th";
}
chosenSAtmp = GuiChoose.one("Select " + num + " spell to copy to stack", tgtSpells);
chosenSAs.add(chosenSAtmp);
tgtSpells.remove(chosenSAtmp);
} else {
chosenSAs.add(tgtSpells.get(multi));
}
}
for (final SpellAbility chosenSAcopy : chosenSAs) {
chosenSAcopy.setActivatingPlayer(controller);
for (int i = 0; i < amount; i++) {
Singletons.getModel().getCardFactory().copySpellontoStack(card, chosenSAcopy.getSourceCard(), chosenSAcopy, true);
}
}
}
else {
SpellAbility chosenSA = null;
if (tgtSpells.size() == 1) {
chosenSA = tgtSpells.get(0);
} else if (sa.getActivatingPlayer().isHuman()) {
chosenSA = GuiChoose.one("Select a spell to copy", tgtSpells);
} else {
chosenSA = tgtSpells.get(0);
}
chosenSA.setActivatingPlayer(controller);
for (int i = 0; i < amount; i++) {
Singletons.getModel().getCardFactory().copySpellontoStack(card, chosenSA.getSourceCard(), chosenSA, true);
}
}
} // end resolve
/**
* <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.
*/
@Override
protected String getStackDescription(java.util.Map<String,String> params, SpellAbility sa) {
final StringBuilder sb = new StringBuilder();
if (!(sa instanceof AbilitySub)) {
sb.append(sa.getSourceCard().getName()).append(" - ");
} else {
sb.append(" ");
}
ArrayList<SpellAbility> tgtSpells;
final Target tgt = sa.getTarget();
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
final Iterator<SpellAbility> it = tgtSpells.iterator();
while (it.hasNext()) {
sb.append(it.next().getSourceCard());
if (it.hasNext()) {
sb.append(", ");
}
}
int amount = 1;
if (params.containsKey("Amount")) {
amount = AbilityFactory.calculateAmount(sa.getSourceCard(), params.get("Amount"), sa);
}
if (amount > 1) {
sb.append(amount).append(" times");
}
sb.append(".");
// TODO probably add an optional "You may choose new targets..."
return sb.toString();
}
} // end class AbilityFactory_Copy

View File

@@ -0,0 +1,180 @@
package forge.card.abilityfactory.effects;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import forge.Card;
import forge.CardLists;
import forge.GameActionUtil;
import forge.Singletons;
import forge.card.abilityfactory.AbilityFactory;
import forge.card.abilityfactory.SpellEffect;
import forge.card.cardfactory.CardFactoryUtil;
import forge.card.spellability.AbilitySub;
import forge.card.spellability.SpellAbility;
import forge.game.zone.ZoneType;
import forge.util.Expressions;
public class RepeatEffect extends SpellEffect {
/**
* <p>
* repeatStackDescription.
* </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.
*/
@Override
protected String getStackDescription(java.util.Map<String,String> params, SpellAbility sa) {
final StringBuilder sb = new StringBuilder();
final Card host = sa.getSourceCard();
if (!(sa instanceof AbilitySub)) {
sb.append(host.getName()).append(" -");
}
sb.append(" ");
if (params.containsKey("StackDescription")) {
final String desc = params.get("StackDescription");
if (!desc.equals("None")) {
sb.append(params.get("StackDescription"));
}
} else {
sb.append("Repeat something. Somebody should really write a better StackDescription!");
}
return sb.toString();
} // end repeatStackDescription()
/**
* <p>
* repeatResolve.
* </p>
*
* @param AF
* a {@link forge.card.abilityfactory.AbilityFactory} object.
* @param SA
* a {@link forge.card.spellability.SpellAbility} object.
*/
@Override
public void resolve(java.util.Map<String,String> params, SpellAbility sa) {
final AbilityFactory afRepeat = new AbilityFactory();
Card source = sa.getSourceCard();
// setup subability to repeat
final SpellAbility repeat = afRepeat.getAbility(sa.getSourceCard().getSVar(params.get("RepeatSubAbility")), source);
repeat.setActivatingPlayer(sa.getActivatingPlayer());
((AbilitySub) repeat).setParent(sa);
Integer maxRepeat = null;
if (params.containsKey("MaxRepeat")) {
maxRepeat = AbilityFactory.calculateAmount(sa.getSourceCard(), params.get("MaxRepeat"), sa);
}
//execute repeat ability at least once
int count = 0;
do {
AbilityFactory.resolve(repeat, false);
count++;
if (maxRepeat != null && maxRepeat <= count) {
// TODO Replace Infinite Loop Break with a game draw. Here are the scenarios that can cause this:
// Helm of Obedience vs Graveyard to Library replacement effect
StringBuilder infLoop = new StringBuilder(sa.getSourceCard().toString());
infLoop.append(" - To avoid an infinite loop, this repeat has been broken ");
infLoop.append(" and the game will now continue in the current state, ending the loop early. ");
infLoop.append("Once Draws are available this probably should change to a Draw.");
System.out.println(infLoop.toString());
break;
}
} while (checkRepeatConditions(params, sa));
}
// end class AbilityFactory_Repeat
/**
* <p>
* checkRepeatConditions.
* </p>
*
* @param AF
* a {@link forge.card.abilityfactory.AbilityFactory} object.
* @param SA
* a {@link forge.card.spellability.SpellAbility} object.
*/
private boolean checkRepeatConditions(final Map<String, String> params, final SpellAbility sa) {
//boolean doAgain = false;
if (params.containsKey("RepeatPresent")) {
final String repeatPresent = params.get("RepeatPresent");
List<Card> list = new ArrayList<Card>();
String repeatCompare = "GE1";
if (params.containsKey("RepeatCompare")) {
repeatCompare = params.get("RepeatCompare");
}
if (params.containsKey("RepeatDefined")) {
list.addAll(AbilityFactory.getDefinedCards(sa.getSourceCard(), params.get("RepeatDefined"), sa));
} else {
list = Singletons.getModel().getGame().getCardsIn(ZoneType.Battlefield);
}
list = CardLists.getValidCards(list, repeatPresent.split(","), sa.getActivatingPlayer(), sa.getSourceCard());
int right;
final String rightString = repeatCompare.substring(2);
try { // If this is an Integer, just parse it
right = Integer.parseInt(rightString);
} catch (final NumberFormatException e) { // Otherwise, grab it from
// the
// SVar
right = CardFactoryUtil.xCount(sa.getSourceCard(), sa.getSourceCard().getSVar(rightString));
}
final int left = list.size();
if (!Expressions.compare(left, repeatCompare, right)) {
return false;
}
}
if (params.containsKey("RepeatCheckSVar")) {
String sVarOperator = "GE";
String sVarOperand = "1";
if (params.containsKey("RepeatSVarCompare")) {
sVarOperator = params.get("RepeatSVarCompare").substring(0, 2);
sVarOperand = params.get("RepeatSVarCompare").substring(2);
}
final int svarValue = AbilityFactory.calculateAmount(sa.getSourceCard(), params.get("RepeatCheckSVar"), sa);
final int operandValue = AbilityFactory.calculateAmount(sa.getSourceCard(), sVarOperand, sa);
if (!Expressions.compare(svarValue, sVarOperator, operandValue)) {
return false;
}
}
if (params.containsKey("RepeatOptional")) {
if (sa.getActivatingPlayer().isComputer()) {
//TODO add logic to have computer make better choice (ArsenalNut)
return false;
} else {
final StringBuilder sb = new StringBuilder();
sb.append("Do you want to repeat this process again?");
if (!GameActionUtil.showYesNoDialog(sa.getSourceCard(), sb.toString())) {
return false;
}
}
}
return true;
}
}