mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-20 12:48:00 +00:00
AF: Copy, repeat
This commit is contained in:
8
.gitattributes
vendored
8
.gitattributes
vendored
@@ -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
|
||||
|
||||
@@ -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")) {
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
}
|
||||
141
src/main/java/forge/card/abilityfactory/ai/CopyPermanentAi.java
Normal file
141
src/main/java/forge/card/abilityfactory/ai/CopyPermanentAi.java
Normal 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.
|
||||
*/
|
||||
|
||||
}
|
||||
43
src/main/java/forge/card/abilityfactory/ai/RepeatAi.java
Normal file
43
src/main/java/forge/card/abilityfactory/ai/RepeatAi.java
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user