AF: Cleanup, StoreSVar, Unattach

This commit is contained in:
Maxmtg
2012-11-04 15:42:10 +00:00
parent 2f2ffcd22e
commit a3e8e6706e
13 changed files with 903 additions and 895 deletions

9
.gitattributes vendored
View File

@@ -12463,8 +12463,7 @@ src/main/java/forge/card/abilityfactory/AbilityFactory.java svneol=native#text/p
src/main/java/forge/card/abilityfactory/AbilityFactoryAttach.java svneol=native#text/plain
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/AbilityFactoryStoreSVar.java -text
src/main/java/forge/card/abilityfactory/CleanUpEffect.java -text
src/main/java/forge/card/abilityfactory/CommonAbility.java -text
src/main/java/forge/card/abilityfactory/CommonDrawback.java svneol=native#text/plain
src/main/java/forge/card/abilityfactory/CommonSpell.java -text
@@ -12477,6 +12476,7 @@ 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/ChangeZoneAllAi.java -text
src/main/java/forge/card/abilityfactory/ai/ChooseCardAi.java -text
src/main/java/forge/card/abilityfactory/ai/ChooseCardNameAi.java -text
src/main/java/forge/card/abilityfactory/ai/ChooseColorAi.java -text
@@ -12544,12 +12544,14 @@ src/main/java/forge/card/abilityfactory/ai/ScryAi.java -text
src/main/java/forge/card/abilityfactory/ai/SetStateAi.java -text
src/main/java/forge/card/abilityfactory/ai/SetStateAllAi.java -text
src/main/java/forge/card/abilityfactory/ai/ShuffleAi.java -text
src/main/java/forge/card/abilityfactory/ai/StoreSVarAi.java -text
src/main/java/forge/card/abilityfactory/ai/TapAi.java -text
src/main/java/forge/card/abilityfactory/ai/TapAiBase.java -text
src/main/java/forge/card/abilityfactory/ai/TapAllAi.java -text
src/main/java/forge/card/abilityfactory/ai/TapOrUntapAi.java -text
src/main/java/forge/card/abilityfactory/ai/TokenAi.java -text
src/main/java/forge/card/abilityfactory/ai/TwoPilesAi.java -text
src/main/java/forge/card/abilityfactory/ai/UnattachAllAi.java -text
src/main/java/forge/card/abilityfactory/ai/UntapAi.java -text
src/main/java/forge/card/abilityfactory/ai/UntapAllAi.java -text
src/main/java/forge/card/abilityfactory/effects/AddTurnEffect.java -text
@@ -12557,6 +12559,7 @@ src/main/java/forge/card/abilityfactory/effects/AnimateAllEffect.java -text
src/main/java/forge/card/abilityfactory/effects/AnimateEffect.java -text
src/main/java/forge/card/abilityfactory/effects/AnimateEffectBase.java svneol=native#text/plain
src/main/java/forge/card/abilityfactory/effects/BondEffect.java -text
src/main/java/forge/card/abilityfactory/effects/ChangeZoneAllEffect.java -text
src/main/java/forge/card/abilityfactory/effects/ChooseCardEffect.java -text
src/main/java/forge/card/abilityfactory/effects/ChooseCardNameEffect.java -text
src/main/java/forge/card/abilityfactory/effects/ChooseColorEffect.java -text
@@ -12629,11 +12632,13 @@ src/main/java/forge/card/abilityfactory/effects/ScryEffect.java -text
src/main/java/forge/card/abilityfactory/effects/SetStateAllEffect.java -text
src/main/java/forge/card/abilityfactory/effects/SetStateEffect.java -text
src/main/java/forge/card/abilityfactory/effects/ShuffleEffect.java -text
src/main/java/forge/card/abilityfactory/effects/StoreSVarEffect.java -text
src/main/java/forge/card/abilityfactory/effects/TapAllEffect.java -text
src/main/java/forge/card/abilityfactory/effects/TapEffect.java -text
src/main/java/forge/card/abilityfactory/effects/TapOrUntapEffect.java -text
src/main/java/forge/card/abilityfactory/effects/TokenEffect.java svneol=native#text/plain
src/main/java/forge/card/abilityfactory/effects/TwoPilesEffect.java -text
src/main/java/forge/card/abilityfactory/effects/UnattachAllEffect.java -text
src/main/java/forge/card/abilityfactory/effects/UntapAllEffect.java -text
src/main/java/forge/card/abilityfactory/effects/UntapEffect.java -text
src/main/java/forge/card/abilityfactory/package-info.java svneol=native#text/plain

View File

@@ -471,9 +471,8 @@ public class AbilityFactory {
}
else if (this.api.equals("Cleanup")) {
if (this.isDb) {
spellAbility = AbilityFactoryCleanup.getDrawback(this);
}
ai = new AlwaysPlayAi();
se = new CleanUpEffect();
}
else if (this.api.equals("Clone")) {
@@ -810,13 +809,8 @@ public class AbilityFactory {
}
else if (this.api.equals("StoreSVar")) {
if (this.isAb) {
spellAbility = AbilityFactoryStoreSVar.createAbilityStoreSVar(this);
} else if (this.isSp) {
spellAbility = AbilityFactoryStoreSVar.createSpellStoreSVar(this);
} else if (this.isDb) {
spellAbility = AbilityFactoryStoreSVar.createDrawbackStoreSVar(this);
}
ai = new StoreSVarAi();
se = new StoreSVarEffect();
}
else if (this.api.equals("Tap")) {
@@ -845,13 +839,8 @@ public class AbilityFactory {
}
else if (this.api.equals("UnattachAll")) {
if (this.isAb) {
spellAbility = AbilityFactoryAttach.createAbilityUnattachAll(this);
} else if (this.isSp) {
spellAbility = AbilityFactoryAttach.createSpellUnattachAll(this);
} else if (this.isDb) {
spellAbility = AbilityFactoryAttach.createDrawbackUnattachAll(this);
}
ai = new UnattachAllAi();
se = new UnattachAllEffect();
}
else if (this.api.equals("Untap")) {

View File

@@ -24,6 +24,7 @@ import java.util.List;
import java.util.Map;
import java.util.Random;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
@@ -1446,402 +1447,5 @@ public class AbilityFactoryAttach {
// ************************ UnattachAll *************************
// **************************************************************
/**
* Creates the ability unattachAll.
*
* @param af
* the aF
* @return the spell ability
*/
public static SpellAbility createAbilityUnattachAll(final AbilityFactory af) {
class AbilityUnattachAll extends AbilityActivated {
public AbilityUnattachAll(final Card ca, final Cost co, final Target t) {
super(ca, co, t);
}
@Override
public AbilityActivated getCopy() {
AbilityActivated res = new AbilityUnattachAll(getSourceCard(),
getPayCosts(), getTarget() == null ? null : new Target(getTarget()));
CardFactoryUtil.copySpellAbility(this, res);
return res;
}
private static final long serialVersionUID = 5946312226232487294L;
@Override
public boolean canPlayAI() {
return AbilityFactoryAttach.unattachAllCanPlayAI(getActivatingPlayer(), af, this);
}
@Override
public void resolve() {
AbilityFactoryAttach.unattachAllResolve(af, this);
}
@Override
public String getStackDescription() {
return AbilityFactoryAttach.unattachAllStackDescription(af, this);
}
@Override
public boolean doTrigger(final boolean mandatory) {
return AbilityFactoryAttach.unattachAllDoTriggerAI(getActivatingPlayer(), af, this, mandatory);
}
}
final SpellAbility abUnattachAll = new AbilityUnattachAll(af.getHostCard(), af.getAbCost(), af.getAbTgt());
return abUnattachAll;
}
/**
* Creates the spell unattachAll.
*
* @param af
* the AbilityFactory
* @return the spell ability
*/
public static SpellAbility createSpellUnattachAll(final AbilityFactory af) {
final SpellAbility spUnattachAll = new Spell(af.getHostCard(), af.getAbCost(), af.getAbTgt()) {
private static final long serialVersionUID = 5531073401713526341L;
@Override
public boolean canPlayAI() {
return AbilityFactoryAttach.unattachAllCanPlayAI(getActivatingPlayer(), af, this);
}
@Override
public void resolve() {
AbilityFactoryAttach.unattachAllResolve(af, this);
}
@Override
public String getStackDescription() {
return AbilityFactoryAttach.unattachAllStackDescription(af, this);
}
};
return spUnattachAll;
}
// Attach Drawback
/**
* Creates the drawback unattachAll.
*
* @param af
* the aF
* @return the spell ability
*/
public static SpellAbility createDrawbackUnattachAll(final AbilityFactory af) {
class DrawbackUnattachAll extends AbilitySub {
public DrawbackUnattachAll(final Card ca, final Target t) {
super(ca, t);
}
@Override
public AbilitySub getCopy() {
AbilitySub res = new DrawbackUnattachAll(getSourceCard(),
getTarget() == null ? null : new Target(getTarget()));
CardFactoryUtil.copySpellAbility(this, res);
return res;
}
private static final long serialVersionUID = 9007743612927046143L;
@Override
public void resolve() {
AbilityFactoryAttach.unattachAllResolve(af, this);
}
@Override
public boolean chkAIDrawback() {
return AbilityFactoryAttach.unattachAllPlayDrawbackAI(getActivatingPlayer(), af, this);
}
@Override
public String getStackDescription() {
return AbilityFactoryAttach.unattachAllStackDescription(af, this);
}
@Override
public boolean doTrigger(final boolean mandatory) {
return AbilityFactoryAttach.unattachAllDoTriggerAI(getActivatingPlayer(), af, this, mandatory);
}
}
final SpellAbility dbUnattachAll = new DrawbackUnattachAll(af.getHostCard(), af.getAbTgt());
return dbUnattachAll;
}
/**
* UnattachAll stack description.
*
* @param af
* the af
* @param sa
* the sa
* @return the string
*/
private static String unattachAllStackDescription(final AbilityFactory af, final SpellAbility sa) {
final StringBuilder sb = new StringBuilder();
if (sa instanceof AbilitySub) {
sb.append(" ");
} else {
sb.append(sa.getSourceCard()).append(" - ");
}
sb.append("Unattach all valid Equipment and Auras from ");
ArrayList<Object> targets;
// Should never allow more than one Attachment per card
final Target tgt = sa.getTarget();
if (tgt != null) {
targets = tgt.getTargets();
} else {
targets = AbilityFactory.getDefinedObjects(sa.getSourceCard(), af.getMapParams().get("Defined"), sa);
}
for (final Object o : targets) {
sb.append(o).append(" ");
}
final AbilitySub abSub = sa.getSubAbility();
if (abSub != null) {
sb.append(abSub.getStackDescription());
}
return sb.toString();
}
private static boolean unattachAllCanPlayAI(final Player ai, final AbilityFactory af, final SpellAbility sa) {
final Random r = MyRandom.getRandom();
final Cost abCost = sa.getPayCosts();
final Card source = sa.getSourceCard();
if (abCost != null) {
// No Aura spells have Additional Costs
}
// prevent run-away activations - first time will always return true
boolean chance = r.nextFloat() <= .9;
// Attach spells always have a target
final Target tgt = sa.getTarget();
if (tgt != null) {
tgt.resetTargets();
}
if (abCost != null && abCost.getTotalMana().contains("X") && source.getSVar("X").equals("Count$xPaid")) {
final int xPay = ComputerUtil.determineLeftoverMana(sa, ai);
if (xPay == 0) {
return false;
}
source.setSVar("PayX", Integer.toString(xPay));
}
if (Singletons.getModel().getGame().getPhaseHandler().getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY)
&& !"Curse".equals(af.getMapParams().get("AILogic"))) {
return false;
}
return chance;
}
private static boolean unattachAllDoTriggerAI(final Player ai, final AbilityFactory af, final SpellAbility sa, final boolean mandatory) {
final Map<String, String> params = af.getMapParams();
final Card card = sa.getSourceCard();
if (!ComputerUtil.canPayCost(sa, ai)) {
// usually not mandatory
return false;
}
final Player opp = ai.getOpponent();
// Check if there are any valid targets
ArrayList<Object> targets = new ArrayList<Object>();
final Target tgt = sa.getTarget();
if (tgt == null) {
targets = AbilityFactory.getDefinedObjects(sa.getSourceCard(), params.get("Defined"), sa);
}
if (!mandatory && card.isEquipment() && !targets.isEmpty()) {
Card newTarget = (Card) targets.get(0);
//don't equip human creatures
if (newTarget.getController().equals(opp)) {
return false;
}
//don't equip a worse creature
if (card.isEquipping()) {
Card oldTarget = card.getEquipping().get(0);
if (CardFactoryUtil.evaluateCreature(oldTarget) > CardFactoryUtil.evaluateCreature(newTarget)) {
return false;
}
}
}
// check SubAbilities DoTrigger?
final AbilitySub abSub = sa.getSubAbility();
if (abSub != null) {
return abSub.doTrigger(mandatory);
}
return true;
}
private static void unattachAllResolve(final AbilityFactory af, final SpellAbility sa) {
final Map<String, String> params = af.getMapParams();
Card source = sa.getSourceCard();
ArrayList<Object> targets;
final Target tgt = sa.getTarget();
if (tgt != null) {
targets = tgt.getTargets();
} else {
targets = AbilityFactory.getDefinedObjects(source, params.get("Defined"), sa);
}
// If Cast Targets will be checked on the Stack
for (final Object o : targets) {
String valid = params.get("UnattachValid");
List<Card> unattachList = Singletons.getModel().getGame().getCardsIn(ZoneType.Battlefield);
unattachList = CardLists.getValidCards(unattachList, valid.split(","), source.getController(), source);
for (final Card c : unattachList) {
AbilityFactoryAttach.handleUnattachment(o, c, af);
}
}
}
private static void handleUnattachment(final Object o, final Card cardToUnattach, final AbilityFactory af) {
if (o instanceof Card) {
final Card c = (Card) o;
if (cardToUnattach.isAura()) {
//final boolean gainControl = "GainControl".equals(af.getMapParams().get("AILogic"));
//AbilityFactoryAttach.handleUnattachAura(cardToUnattach, c, gainControl);
} else if (cardToUnattach.isEquipment()) {
if (cardToUnattach.isEquipping() && c.getEquippedBy().contains(cardToUnattach)) {
cardToUnattach.unEquipCard(cardToUnattach.getEquipping().get(0));
}
//TODO - unfortify would also be handled here
}
} else if (o instanceof Player) {
final Player p = (Player) o;
if (cardToUnattach.isAura() && p.getEnchantedBy().contains(cardToUnattach)) {
//AbilityFactoryAttach.handleUnattachAura(cardToUnattach, p, false);
}
}
}
/* this isn't modifed to handled unattach yet, but should be for things like Remove Enchantments, etc.
private static void handleUnattachAura(final Card card, final GameEntity tgt, final boolean gainControl) {
if (card.isEnchanting()) {
// If this Card is already Enchanting something
// Need to unenchant it, then clear out the commands
final GameEntity oldEnchanted = card.getEnchanting();
card.removeEnchanting(oldEnchanted);
card.clearEnchantCommand();
card.clearUnEnchantCommand();
card.clearTriggers(); // not sure if cleartriggers is needed?
}
if (gainControl) {
// Handle GainControl Auras
final Player[] pl = new Player[1];
if (tgt instanceof Card) {
pl[0] = ((Card) tgt).getController();
} else {
pl[0] = (Player) tgt;
}
final Command onEnchant = new Command() {
private static final long serialVersionUID = -2519887209491512000L;
@Override
public void execute() {
final Card crd = card.getEnchantingCard();
if (crd == null) {
return;
}
pl[0] = crd.getController();
crd.addController(card);
} // execute()
}; // Command
final Command onUnEnchant = new Command() {
private static final long serialVersionUID = 3426441132121179288L;
@Override
public void execute() {
final Card crd = card.getEnchantingCard();
if (crd == null) {
return;
}
if (AllZoneUtil.isCardInPlay(crd)) {
crd.removeController(card);
}
} // execute()
}; // Command
final Command onChangesControl = new Command() {
private static final long serialVersionUID = -65903786170234039L;
@Override
public void execute() {
final Card crd = card.getEnchantingCard();
if (crd == null) {
return;
}
crd.removeController(card); // This looks odd, but will
// simply refresh controller
crd.addController(card);
} // execute()
}; // Command
// Add Enchant Commands for Control changers
card.addEnchantCommand(onEnchant);
card.addUnEnchantCommand(onUnEnchant);
card.addChangeControllerCommand(onChangesControl);
}
final Command onLeavesPlay = new Command() {
private static final long serialVersionUID = -639204333673364477L;
@Override
public void execute() {
final GameEntity entity = card.getEnchanting();
if (entity == null) {
return;
}
card.unEnchantEntity(entity);
}
}; // Command
card.addLeavesPlayCommand(onLeavesPlay);
card.enchantEntity(tgt);
}
*/
private static boolean unattachAllPlayDrawbackAI(final Player ai, final AbilityFactory af, final SpellAbility sa) {
// AI should only activate this during Human's turn
boolean chance = AbilityFactoryAttach.unattachAllCanPlayAI(ai, af, sa);
final AbilitySub subAb = sa.getSubAbility();
if (subAb != null) {
chance &= subAb.chkAIDrawback();
}
return chance;
}
}

View File

@@ -1,124 +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.Map;
import forge.Card;
import forge.Singletons;
import forge.card.cardfactory.CardFactoryUtil;
import forge.card.spellability.AbilitySub;
import forge.card.spellability.SpellAbility;
import forge.card.spellability.Target;
// Cleanup is not the same as other AFs, it is only used as a Drawback, and only used to Cleanup particular card states
// That need to be reset. I'm creating this to clear Remembered Cards at the
// end of an Effect so they don't get shown on a card
// After the effect finishes resolving.
/**
* <p>
* AbilityFactory_Cleanup class.
* </p>
*
* @author Forge
* @version $Id$
*/
public final class AbilityFactoryCleanup {
private AbilityFactoryCleanup() {
throw new AssertionError();
}
/**
* <p>
* getDrawback.
* </p>
*
* @param af
* a {@link forge.card.abilityfactory.AbilityFactory} object.
* @return a {@link forge.card.spellability.AbilitySub} object.
*/
public static AbilitySub getDrawback(final AbilityFactory af) {
class DrawbackCleanup extends AbilitySub {
public DrawbackCleanup(final Card ca, final Target t) {
super(ca, t);
}
@Override
public AbilitySub getCopy() {
AbilitySub res = new DrawbackCleanup(getSourceCard(),
getTarget() == null ? null : new Target(getTarget()));
CardFactoryUtil.copySpellAbility(this, res);
return res;
}
private static final long serialVersionUID = 6192972525033429820L;
@Override
public boolean chkAIDrawback() {
return true;
}
@Override
public boolean doTrigger(final boolean mandatory) {
return true;
}
@Override
public void resolve() {
AbilityFactoryCleanup.doResolve(af, this);
}
}
final AbilitySub drawback = new DrawbackCleanup(af.getHostCard(), af.getAbTgt());
return drawback;
}
/**
* <p>
* doResolve.
* </p>
*
* @param AF
* a {@link forge.card.abilityfactory.AbilityFactory} object.
* @param sa
* a {@link forge.card.spellability.SpellAbility} object.
*/
private static void doResolve(final AbilityFactory af, final SpellAbility sa) {
final Map<String, String> params = af.getMapParams();
Card source = sa.getSourceCard();
if (params.containsKey("ClearRemembered")) {
source.clearRemembered();
Singletons.getModel().getGame().getCardState(source).clearRemembered();
}
if (params.containsKey("ClearImprinted")) {
source.clearImprinted();
}
if (params.containsKey("ClearChosenX")) {
source.setSVar("ChosenX", "");
}
if (params.containsKey("ClearChosenY")) {
source.setSVar("ChosenY", "");
}
if (params.containsKey("ClearTriggered")) {
Singletons.getModel().getGame().getTriggerHandler().clearDelayedTrigger(source);
}
}
} // end class AbilityFactory_Cleanup

View File

@@ -1,352 +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.Map;
import forge.Card;
import forge.Singletons;
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.cost.Cost;
import forge.card.spellability.Target;
import forge.game.phase.CombatUtil;
import forge.game.player.ComputerUtil;
import forge.game.player.Player;
/**
* <p>
* AbilityFactoryStoreSVar class.
* </p>
*
* @author Forge
* @version $Id: AbilityFactoryStoreSVar.java 15090 2012-04-07 12:50:31Z Max mtg $
*/
public class AbilityFactoryStoreSVar {
/**
* <p>
* createAbilityStoreSVar.
* </p>
*
* @param abilityFactory
* a {@link forge.card.abilityfactory.AbilityFactory} object.
* @return a {@link forge.card.spellability.SpellAbility} object.
*/
public static SpellAbility createAbilityStoreSVar(final AbilityFactory abilityFactory) {
class AbilityStoreSVar extends AbilityActivated {
public AbilityStoreSVar(final Card ca, final Cost co, final Target t) {
super(ca, co, t);
}
@Override
public AbilityActivated getCopy() {
AbilityActivated res = new AbilityStoreSVar(getSourceCard(),
getPayCosts(), getTarget() == null ? null : new Target(getTarget()));
CardFactoryUtil.copySpellAbility(this, res);
return res;
}
private static final long serialVersionUID = -7299561150243337080L;
private final AbilityFactory af = abilityFactory;
@Override
public String getStackDescription() {
return AbilityFactoryStoreSVar.storeSVarStackDescription(this.af, this);
}
@Override
public boolean canPlayAI() {
return AbilityFactoryStoreSVar.storeSVarCanPlayAI(this.af, this);
}
@Override
public void resolve() {
AbilityFactoryStoreSVar.storeSVarResolve(this.af, this);
}
@Override
public boolean doTrigger(final boolean mandatory) {
return AbilityFactoryStoreSVar.storeSVarDoTriggerAI(getActivatingPlayer(), this.af, this, mandatory);
}
}
final SpellAbility abStoreSVar = new AbilityStoreSVar(abilityFactory.getHostCard(), abilityFactory.getAbCost(),
abilityFactory.getAbTgt());
return abStoreSVar;
}
/**
* <p>
* createSpellStoreSVar.
* </p>
*
* @param abilityFactory
* a {@link forge.card.abilityfactory.AbilityFactory} object.
* @return a {@link forge.card.spellability.SpellAbility} object.
*/
public static SpellAbility createSpellStoreSVar(final AbilityFactory abilityFactory) {
final SpellAbility spStoreSVar = new Spell(abilityFactory.getHostCard(), abilityFactory.getAbCost(),
abilityFactory.getAbTgt()) {
private static final long serialVersionUID = 6631124959690157874L;
private final AbilityFactory af = abilityFactory;
@Override
public String getStackDescription() {
// when getStackDesc is called, just build exactly what is
// happening
return AbilityFactoryStoreSVar.storeSVarStackDescription(this.af, this);
}
@Override
public boolean canPlayAI() {
return AbilityFactoryStoreSVar.storeSVarCanPlayAI(this.af, this);
}
@Override
public void resolve() {
AbilityFactoryStoreSVar.storeSVarResolve(this.af, this);
}
};
return spStoreSVar;
}
/**
* <p>
* createDrawbackStoreSVar.
* </p>
*
* @param abilityFactory
* a {@link forge.card.abilityfactory.AbilityFactory} object.
* @return a {@link forge.card.spellability.SpellAbility} object.
*/
public static SpellAbility createDrawbackStoreSVar(final AbilityFactory abilityFactory) {
class DrawbackStoreSVar extends AbilitySub {
public DrawbackStoreSVar(final Card ca, final Target t) {
super(ca, t);
}
@Override
public AbilitySub getCopy() {
AbilitySub res = new DrawbackStoreSVar(getSourceCard(),
getTarget() == null ? null : new Target(getTarget()));
CardFactoryUtil.copySpellAbility(this, res);
return res;
}
private static final long serialVersionUID = 6631124959690157874L;
private final AbilityFactory af = abilityFactory;
@Override
public String getStackDescription() {
// when getStackDesc is called, just build exactly what is
// happening
return AbilityFactoryStoreSVar.storeSVarStackDescription(this.af, this);
}
@Override
public boolean canPlayAI() {
return AbilityFactoryStoreSVar.storeSVarCanPlayAI(this.af, this);
}
@Override
public void resolve() {
AbilityFactoryStoreSVar.storeSVarResolve(this.af, this);
}
@Override
public boolean chkAIDrawback() {
boolean randomReturn = true;
final AbilitySub subAb = this.getSubAbility();
if (subAb != null) {
randomReturn &= subAb.chkAIDrawback();
}
return randomReturn;
}
@Override
public boolean doTrigger(final boolean mandatory) {
return AbilityFactoryStoreSVar.storeSVarDoTriggerAI(getActivatingPlayer(), this.af, this, mandatory);
}
}
final SpellAbility dbStoreSVar = new DrawbackStoreSVar(abilityFactory.getHostCard(), abilityFactory.getAbTgt());
return dbStoreSVar;
}
/**
* <p>
* storeSVarStackDescription.
* </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.
*/
public static String storeSVarStackDescription(final AbilityFactory af, final SpellAbility sa) {
final Map<String, String> params = af.getMapParams();
final StringBuilder sb = new StringBuilder();
if (sa instanceof AbilitySub) {
sb.append(" ");
} else {
sb.append(sa.getSourceCard().getName()).append(" - ");
}
if (params.containsKey("StackDescription")) {
sb.append(params.get("StackDescription").replaceAll("CARDNAME", sa.getSourceCard().getName()));
return sb.toString();
}
sb.append(sa.getDescription());
final AbilitySub abSub = sa.getSubAbility();
if (abSub != null) {
sb.append(abSub.getStackDescription());
}
return sb.toString();
}
/**
* <p>
* storeSVarCanPlayAI.
* </p>
*
* @param af
* a {@link forge.card.abilityfactory.AbilityFactory} object.
* @param sa
* a {@link forge.card.spellability.SpellAbility} object.
* @return a boolean.
*/
public static boolean storeSVarCanPlayAI(final AbilityFactory af, final SpellAbility sa) {
//Tree of Redemption
final Player ai = sa.getActivatingPlayer();
final Card source = sa.getSourceCard();
if (ComputerUtil.waitForBlocking(sa) || ai.getLife() + 1 >= source.getNetDefense()
|| (ai.getLife() > 5 && !CombatUtil.lifeInSeriousDanger(ai, Singletons.getModel().getGame().getCombat()))) {
return false;
}
final AbilitySub subAb = sa.getSubAbility();
if (subAb != null && !subAb.chkAIDrawback()) {
return false;
}
return true;
}
/**
* <p>
* storeSVarDoTriggerAI.
* </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.
*/
public static boolean storeSVarDoTriggerAI(final Player ai, final AbilityFactory af, final SpellAbility sa, final boolean mandatory) {
if (!ComputerUtil.canPayCost(sa, ai) && !mandatory) {
// payment it's usually
// not mandatory
return false;
}
// check SubAbilities DoTrigger?
final AbilitySub abSub = sa.getSubAbility();
if (abSub != null) {
return abSub.doTrigger(mandatory);
}
return true;
}
/**
* <p>
* storeSVarResolve.
* </p>
*
* @param af
* a {@link forge.card.abilityfactory.AbilityFactory} object.
* @param sa
* a {@link forge.card.spellability.SpellAbility} object.
*/
public static void storeSVarResolve(final AbilityFactory af, final SpellAbility sa) {
//SVar$ OldToughness | Type$ Count | Expression$ CardToughness
final Map<String, String> params = af.getMapParams();
Card source = sa.getSourceCard();
String key = null;
String type = null;
String expr = null;
if (params.containsKey("SVar")) {
key = params.get("SVar");
}
if (params.containsKey("Type")) {
type = params.get("Type");
}
if (params.containsKey("Expression")) {
expr = params.get("Expression");
}
if (key == null || type == null || expr == null) {
System.out.println("SVar, Type and Expression paramaters required for StoreSVar. They are missing for " + source.getName());
return;
}
int value = 0;
if (type.equals("Count")) {
value = CardFactoryUtil.xCount(source, expr);
}
else if (type.equals("Number")) {
value = Integer.valueOf(expr);
}
else if (type.equals("CountSVar")) {
value = CardFactoryUtil.xCount(source, "SVar$" + expr);
}
//TODO For other types call a different function
StringBuilder numBuilder = new StringBuilder();
numBuilder.append("Number$");
numBuilder.append(value);
source.setSVar(key, numBuilder.toString());
SpellAbility root = sa.getRootSpellAbility();
while(root != null) {
root.setSVar(key, numBuilder.toString());
root = root.getSubAbility();
}
}
} // end class AbilityFactorystoreSVar

View File

@@ -0,0 +1,36 @@
package forge.card.abilityfactory;
import java.util.Map;
import forge.Card;
import forge.Singletons;
import forge.card.spellability.SpellAbility;
public class CleanUpEffect 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) {
Card source = sa.getSourceCard();
if (params.containsKey("ClearRemembered")) {
source.clearRemembered();
Singletons.getModel().getGame().getCardState(source).clearRemembered();
}
if (params.containsKey("ClearImprinted")) {
source.clearImprinted();
}
if (params.containsKey("ClearChosenX")) {
source.setSVar("ChosenX", "");
}
if (params.containsKey("ClearChosenY")) {
source.setSVar("ChosenY", "");
}
if (params.containsKey("ClearTriggered")) {
Singletons.getModel().getGame().getTriggerHandler().clearDelayedTrigger(source);
}
}
} // end class AbilityFactory_Cleanup

View File

@@ -58,11 +58,10 @@ public class CommonAbility extends AbilityActivated {
@Override
public boolean canPlayAI() {
return ai.canPlayAI(getActivatingPlayer(), params, this);
}
}
@Override
public boolean doTrigger(final boolean mandatory) {
return ai.doTriggerAI(this.getActivatingPlayer(), params, this, mandatory);
}
}

View File

@@ -0,0 +1,297 @@
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.card.abilityfactory.AbilityFactory;
import forge.card.abilityfactory.SpellAiLogic;
import forge.card.cardfactory.CardFactoryUtil;
import forge.card.cost.Cost;
import forge.card.cost.CostUtil;
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 ChangeZoneAllAi 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 ai, Map<String, String> params, SpellAbility sa) {
// Change Zone All, can be any type moving from one zone to another
final Cost abCost = sa.getAbilityFactory().getAbCost();
final Card source = sa.getSourceCard();
final ZoneType destination = ZoneType.smartValueOf(params.get("Destination"));
final ZoneType origin = ZoneType.smartValueOf(params.get("Origin"));
if (abCost != null) {
// AI currently disabled for these costs
if (!CostUtil.checkLifeCost(ai, abCost, source, 4, null)) {
return false;
}
if (!CostUtil.checkDiscardCost(ai, abCost, source)) {
return false;
}
}
final Random r = MyRandom.getRandom();
// prevent run-away activations - first time will always return true
boolean chance = r.nextFloat() <= Math.pow(.6667, sa.getActivationsThisTurn());
// TODO targeting with ChangeZoneAll
// really two types of targeting.
// Target Player has all their types change zones
// or target permanent and do something relative to that permanent
// ex. "Return all Auras attached to target"
// ex. "Return all blocking/blocked by target creature"
final Player opp = ai.getOpponent();
final List<Card> humanType = AbilityFactory.filterListByType(opp.getCardsIn(origin), params.get("ChangeType"), sa);
List<Card> computerType = ai.getCardsIn(origin);
computerType = AbilityFactory.filterListByType(computerType, params.get("ChangeType"), sa);
final Target tgt = sa.getTarget();
// TODO improve restrictions on when the AI would want to use this
// spBounceAll has some AI we can compare to.
if (origin.equals(ZoneType.Hand) || origin.equals(ZoneType.Library)) {
if (tgt != null) {
if (opp.getCardsIn(ZoneType.Hand).isEmpty()
|| !opp.canBeTargetedBy(sa)) {
return false;
}
tgt.resetTargets();
tgt.addTarget(opp);
}
} else if (origin.equals(ZoneType.Battlefield)) {
// this statement is assuming the AI is trying to use this spell
// offensively
// if the AI is using it defensively, then something else needs to
// occur
// if only creatures are affected evaluate both lists and pass only
// if human creatures are more valuable
if (tgt != null) {
if (opp.getCardsIn(ZoneType.Hand).isEmpty()
|| !opp.canBeTargetedBy(sa)) {
return false;
}
tgt.resetTargets();
tgt.addTarget(opp);
computerType.clear();
}
if ((CardLists.getNotType(humanType, "Creature").size() == 0) && (CardLists.getNotType(computerType, "Creature").size() == 0)) {
if ((CardFactoryUtil.evaluateCreatureList(computerType) + 200) >= CardFactoryUtil
.evaluateCreatureList(humanType)) {
return false;
}
} // otherwise evaluate both lists by CMC and pass only if human
// permanents are more valuable
else if ((CardFactoryUtil.evaluatePermanentList(computerType) + 3) >= CardFactoryUtil
.evaluatePermanentList(humanType)) {
return false;
}
// Don't cast during main1?
if (Singletons.getModel().getGame().getPhaseHandler().is(PhaseType.MAIN1, ai)) {
return false;
}
} else if (origin.equals(ZoneType.Graveyard)) {
if (tgt != null) {
if (opp.getCardsIn(ZoneType.Graveyard).isEmpty()
|| !opp.canBeTargetedBy(sa)) {
return false;
}
tgt.resetTargets();
tgt.addTarget(opp);
}
} else if (origin.equals(ZoneType.Exile)) {
} else if (origin.equals(ZoneType.Stack)) {
// time stop can do something like this:
// Origin$ Stack | Destination$ Exile | SubAbility$ DBSkip
// DBSKipToPhase | DB$SkipToPhase | Phase$ Cleanup
// otherwise, this situation doesn't exist
return false;
}
if (destination.equals(ZoneType.Battlefield)) {
if (params.get("GainControl") != null) {
// Check if the cards are valuable enough
if ((CardLists.getNotType(humanType, "Creature").size() == 0) && (CardLists.getNotType(computerType, "Creature").size() == 0)) {
if ((CardFactoryUtil.evaluateCreatureList(computerType) + CardFactoryUtil
.evaluateCreatureList(humanType)) < 400) {
return false;
}
} // otherwise evaluate both lists by CMC and pass only if human
// permanents are less valuable
else if ((CardFactoryUtil.evaluatePermanentList(computerType) + CardFactoryUtil
.evaluatePermanentList(humanType)) < 6) {
return false;
}
} else {
// don't activate if human gets more back than AI does
if ((CardLists.getNotType(humanType, "Creature").size() == 0) && (CardLists.getNotType(computerType, "Creature").size() == 0)) {
if (CardFactoryUtil.evaluateCreatureList(computerType) <= (CardFactoryUtil
.evaluateCreatureList(humanType) + 100)) {
return false;
}
} // otherwise evaluate both lists by CMC and pass only if human
// permanents are less valuable
else if (CardFactoryUtil.evaluatePermanentList(computerType) <= (CardFactoryUtil
.evaluatePermanentList(humanType) + 2)) {
return false;
}
}
}
final AbilitySub subAb = sa.getSubAbility();
if (subAb != null) {
chance &= subAb.chkAIDrawback();
}
return (((r.nextFloat() < .8) || sa.isTrigger()) && chance);
}
/**
* <p>
* changeZoneAllPlayDrawbackAI.
* </p>
*
* @param af
* a {@link forge.card.abilityfactory.AbilityFactory} object.
* @param sa
* a {@link forge.card.spellability.SpellAbility} object.
* @return a boolean.
*/
@Override
public boolean chkAIDrawback(java.util.Map<String,String> params, SpellAbility sa, Player aiPlayer) {
// if putting cards from hand to library and parent is drawing cards
// make sure this will actually do something:
return true;
}
/**
* <p>
* gainLifeDoTriggerAINoCost.
* </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 ai, java.util.Map<String,String> params, SpellAbility sa, boolean mandatory) {
// Change Zone All, can be any type moving from one zone to another
final ZoneType destination = ZoneType.smartValueOf(params.get("Destination"));
final ZoneType origin = ZoneType.smartValueOf(params.get("Origin"));
final Player opp = ai.getOpponent();
final List<Card> humanType = AbilityFactory.filterListByType(opp.getCardsIn(origin), params.get("ChangeType"), sa);
List<Card> computerType = ai.getCardsIn(origin);
computerType = AbilityFactory.filterListByType(computerType, params.get("ChangeType"), sa);
// TODO improve restrictions on when the AI would want to use this
// spBounceAll has some AI we can compare to.
if (origin.equals(ZoneType.Hand) || origin.equals(ZoneType.Library)) {
final Target tgt = sa.getTarget();
if (tgt != null) {
if (opp.getCardsIn(ZoneType.Hand).isEmpty()
|| !opp.canBeTargetedBy(sa)) {
return false;
}
tgt.resetTargets();
tgt.addTarget(opp);
}
} else if (origin.equals(ZoneType.Battlefield)) {
// this statement is assuming the AI is trying to use this spell offensively
// if the AI is using it defensively, then something else needs to occur
// if only creatures are affected evaluate both lists and pass only
// if human creatures are more valuable
if ((CardLists.getNotType(humanType, "Creature").isEmpty()) && (CardLists.getNotType(computerType, "Creature").isEmpty())) {
if (CardFactoryUtil.evaluateCreatureList(computerType) >= CardFactoryUtil
.evaluateCreatureList(humanType)) {
return false;
}
} // otherwise evaluate both lists by CMC and pass only if human
// permanents are more valuable
else if (CardFactoryUtil.evaluatePermanentList(computerType) >= CardFactoryUtil
.evaluatePermanentList(humanType)) {
return false;
}
} else if (origin.equals(ZoneType.Graveyard)) {
final Target tgt = sa.getTarget();
if (tgt != null) {
if (opp.getCardsIn(ZoneType.Graveyard).isEmpty()
|| !opp.canBeTargetedBy(sa)) {
return false;
}
tgt.resetTargets();
tgt.addTarget(opp);
}
} else if (origin.equals(ZoneType.Exile)) {
} else if (origin.equals(ZoneType.Stack)) {
// time stop can do something like this:
// Origin$ Stack | Destination$ Exile | SubAbility$ DBSkip
// DBSKipToPhase | DB$SkipToPhase | Phase$ Cleanup
// otherwise, this situation doesn't exist
return false;
}
if (destination.equals(ZoneType.Battlefield)) {
if (params.get("GainControl") != null) {
// Check if the cards are valuable enough
if ((CardLists.getNotType(humanType, "Creature").size() == 0) && (CardLists.getNotType(computerType, "Creature").size() == 0)) {
if ((CardFactoryUtil.evaluateCreatureList(computerType) + CardFactoryUtil
.evaluateCreatureList(humanType)) < 1) {
return false;
}
} // otherwise evaluate both lists by CMC and pass only if human
// permanents are less valuable
else if ((CardFactoryUtil.evaluatePermanentList(computerType) + CardFactoryUtil
.evaluatePermanentList(humanType)) < 1) {
return false;
}
} else {
// don't activate if human gets more back than AI does
if ((CardLists.getNotType(humanType, "Creature").isEmpty()) && (CardLists.getNotType(computerType, "Creature").isEmpty())) {
if (CardFactoryUtil.evaluateCreatureList(computerType) <= CardFactoryUtil
.evaluateCreatureList(humanType)) {
return false;
}
} // otherwise evaluate both lists by CMC and pass only if human
// permanents are less valuable
else if (CardFactoryUtil.evaluatePermanentList(computerType) <= CardFactoryUtil
.evaluatePermanentList(humanType)) {
return false;
}
}
}
boolean chance = true;
final AbilitySub subAb = sa.getSubAbility();
if (subAb != null) {
chance &= subAb.chkAIDrawback();
}
return chance;
}
}

View File

@@ -0,0 +1,50 @@
package forge.card.abilityfactory.ai;
import forge.Card;
import forge.Singletons;
import forge.card.abilityfactory.SpellAiLogic;
import forge.card.spellability.AbilitySub;
import forge.card.spellability.SpellAbility;
import forge.game.phase.CombatUtil;
import forge.game.player.ComputerUtil;
import forge.game.player.Player;
public class StoreSVarAi extends SpellAiLogic {
@Override
public boolean canPlayAI(Player ai, java.util.Map<String,String> params, SpellAbility sa) {
//Tree of Redemption
final Card source = sa.getSourceCard();
if (ComputerUtil.waitForBlocking(sa) || ai.getLife() + 1 >= source.getNetDefense()
|| (ai.getLife() > 5 && !CombatUtil.lifeInSeriousDanger(ai, Singletons.getModel().getGame().getCombat()))) {
return false;
}
final AbilitySub subAb = sa.getSubAbility();
if (subAb != null && !subAb.chkAIDrawback()) {
return false;
}
return true;
}
@Override
public boolean chkAIDrawback(java.util.Map<String,String> params, SpellAbility sa, Player aiPlayer) {
return true;
};
@Override
public boolean doTriggerAINoCost(Player aiPlayer, java.util.Map<String,String> params, SpellAbility sa, boolean mandatory) {
// check SubAbilities DoTrigger?
final AbilitySub abSub = sa.getSubAbility();
if (abSub != null) {
return abSub.doTrigger(mandatory);
}
return true;
}
}

View File

@@ -0,0 +1,124 @@
package forge.card.abilityfactory.ai;
import java.util.ArrayList;
import java.util.Map;
import java.util.Random;
import forge.Card;
import forge.Singletons;
import forge.card.abilityfactory.AbilityFactory;
import forge.card.abilityfactory.SpellAiLogic;
import forge.card.cardfactory.CardFactoryUtil;
import forge.card.cost.Cost;
import forge.card.spellability.AbilitySub;
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.util.MyRandom;
public class UnattachAllAi 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 ai, Map<String, String> params, SpellAbility sa) {
final Random r = MyRandom.getRandom();
final Cost abCost = sa.getPayCosts();
final Card source = sa.getSourceCard();
if (abCost != null) {
// No Aura spells have Additional Costs
}
// prevent run-away activations - first time will always return true
boolean chance = r.nextFloat() <= .9;
// Attach spells always have a target
final Target tgt = sa.getTarget();
if (tgt != null) {
tgt.resetTargets();
}
if (abCost != null && abCost.getTotalMana().contains("X") && source.getSVar("X").equals("Count$xPaid")) {
final int xPay = ComputerUtil.determineLeftoverMana(sa, ai);
if (xPay == 0) {
return false;
}
source.setSVar("PayX", Integer.toString(xPay));
}
if (Singletons.getModel().getGame().getPhaseHandler().getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY)
&& !"Curse".equals(params.get("AILogic"))) {
return false;
}
return chance;
}
/* (non-Javadoc)
* @see forge.card.abilityfactory.SpellAiLogic#doTriggerAINoCost(forge.game.player.Player, java.util.Map, forge.card.spellability.SpellAbility, boolean)
*/
@Override
public boolean doTriggerAINoCost(Player ai, Map<String, String> params, SpellAbility sa, boolean mandatory) {
final Card card = sa.getSourceCard();
final Player opp = ai.getOpponent();
// Check if there are any valid targets
ArrayList<Object> targets = new ArrayList<Object>();
final Target tgt = sa.getTarget();
if (tgt == null) {
targets = AbilityFactory.getDefinedObjects(sa.getSourceCard(), params.get("Defined"), sa);
}
if (!mandatory && card.isEquipment() && !targets.isEmpty()) {
Card newTarget = (Card) targets.get(0);
//don't equip human creatures
if (newTarget.getController().equals(opp)) {
return false;
}
//don't equip a worse creature
if (card.isEquipping()) {
Card oldTarget = card.getEquipping().get(0);
if (CardFactoryUtil.evaluateCreature(oldTarget) > CardFactoryUtil.evaluateCreature(newTarget)) {
return false;
}
}
}
// check SubAbilities DoTrigger?
final AbilitySub abSub = sa.getSubAbility();
if (abSub != null) {
return abSub.doTrigger(mandatory);
}
return true;
}
@Override
public boolean chkAIDrawback(java.util.Map<String,String> params, SpellAbility sa, Player ai) {
// AI should only activate this during Human's turn
return canPlayAI(ai, params, sa);
}
/**
* UnattachAll stack description.
*
* @param af
* the af
* @param sa
* the sa
* @return the string
*/
}

View File

@@ -0,0 +1,134 @@
package forge.card.abilityfactory.effects;
import java.util.ArrayList;
import java.util.List;
import com.google.common.collect.Iterables;
import forge.Card;
import forge.CardCharacteristicName;
import forge.CardPredicates;
import forge.Singletons;
import forge.card.abilityfactory.AbilityFactory;
import forge.card.abilityfactory.AbilityFactoryAttach;
import forge.card.abilityfactory.SpellEffect;
import forge.card.spellability.SpellAbility;
import forge.card.spellability.Target;
import forge.game.player.Player;
import forge.game.zone.ZoneType;
public class ChangeZoneAllEffect extends SpellEffect {
/**
* <p>
* changeZoneAllStackDescription.
* </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) {
// TODO build Stack Description will need expansion as more cards are added
final String[] desc = sa.getDescription().split(":");
if (desc.length > 1) {
return desc[1];
} else {
return desc[0];
}
}
/**
* <p>
* changeZoneAllResolve.
* </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 ZoneType destination = ZoneType.smartValueOf(params.get("Destination"));
final List<ZoneType> origin = ZoneType.listValueOf(params.get("Origin"));
List<Card> cards = null;
ArrayList<Player> tgtPlayers = null;
final Target tgt = sa.getTarget();
if (tgt != null) {
tgtPlayers = tgt.getTargetPlayers();
} else if (params.containsKey("Defined")) {
tgtPlayers = AbilityFactory.getDefinedPlayers(sa.getSourceCard(), params.get("Defined"), sa);
}
if ((tgtPlayers == null) || tgtPlayers.isEmpty()) {
cards = Singletons.getModel().getGame().getCardsIn(origin);
} else {
cards = tgtPlayers.get(0).getCardsIn(origin);
}
cards = AbilityFactory.filterListByType(cards, params.get("ChangeType"), sa);
if (params.containsKey("ForgetOtherRemembered")) {
sa.getSourceCard().clearRemembered();
}
final String remember = params.get("RememberChanged");
// I don't know if library position is necessary. It's here if it is,
// just in case
final int libraryPos = params.containsKey("LibraryPosition") ? Integer.parseInt(params.get("LibraryPosition"))
: 0;
for (final Card c : cards) {
if (destination.equals(ZoneType.Battlefield)) {
// Auras without Candidates stay in their current location
if (c.isAura()) {
final SpellAbility saAura = AbilityFactoryAttach.getAttachSpellAbility(c);
if (!saAura.getTarget().hasCandidates(saAura, false)) {
continue;
}
}
if (params.containsKey("Tapped")) {
c.setTapped(true);
}
}
if (params.containsKey("GainControl")) {
c.addController(sa.getSourceCard());
Singletons.getModel().getGame().getAction().moveToPlay(c, sa.getActivatingPlayer());
} else {
final Card movedCard = Singletons.getModel().getGame().getAction().moveTo(destination, c, libraryPos);
if (params.containsKey("ExileFaceDown")) {
movedCard.setState(CardCharacteristicName.FaceDown);
}
if (params.containsKey("Tapped")) {
movedCard.setTapped(true);
}
}
if (remember != null) {
Singletons.getModel().getGame().getCardState(sa.getSourceCard()).addRemembered(c);
}
}
// if Shuffle parameter exists, and any amount of cards were owned by
// that player, then shuffle that library
if (params.containsKey("Shuffle")) {
for( Player p : Singletons.getModel().getGame().getPlayers()) {
if (Iterables.any(cards, CardPredicates.isOwner(p))) {
p.shuffle();
}
}
}
}
}

View File

@@ -0,0 +1,73 @@
package forge.card.abilityfactory.effects;
import forge.Card;
import forge.card.abilityfactory.AbilityFactory;
import forge.card.abilityfactory.SpellEffect;
import forge.card.cardfactory.CardFactoryUtil;
import forge.card.spellability.SpellAbility;
public class StoreSVarEffect extends SpellEffect {
/**
* <p>
* storeSVarResolve.
* </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) {
//SVar$ OldToughness | Type$ Count | Expression$ CardToughness
Card source = sa.getSourceCard();
String key = null;
String type = null;
String expr = null;
if (params.containsKey("SVar")) {
key = params.get("SVar");
}
if (params.containsKey("Type")) {
type = params.get("Type");
}
if (params.containsKey("Expression")) {
expr = params.get("Expression");
}
if (key == null || type == null || expr == null) {
System.out.println("SVar, Type and Expression paramaters required for StoreSVar. They are missing for " + source.getName());
return;
}
int value = 0;
if (type.equals("Count")) {
value = CardFactoryUtil.xCount(source, expr);
}
else if (type.equals("Number")) {
value = Integer.valueOf(expr);
}
else if (type.equals("CountSVar")) {
value = CardFactoryUtil.xCount(source, "SVar$" + expr);
}
//TODO For other types call a different function
StringBuilder numBuilder = new StringBuilder();
numBuilder.append("Number$");
numBuilder.append(value);
source.setSVar(key, numBuilder.toString());
SpellAbility root = sa.getRootSpellAbility();
while(root != null) {
root.setSVar(key, numBuilder.toString());
root = root.getSubAbility();
}
}
} // end class AbilityFactorystoreSVar

View File

@@ -0,0 +1,173 @@
package forge.card.abilityfactory.effects;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import forge.Card;
import forge.CardLists;
import forge.GameEntity;
import forge.Singletons;
import forge.card.abilityfactory.SpellEffect;
import forge.card.spellability.SpellAbility;
import forge.card.spellability.Target;
import forge.game.player.Player;
import forge.game.zone.ZoneType;
public class UnattachAllEffect extends SpellEffect {
private void handleUnattachment(final GameEntity o, final Card cardToUnattach) {
if (o instanceof Card) {
final Card c = (Card) o;
if (cardToUnattach.isAura()) {
//final boolean gainControl = "GainControl".equals(af.getMapParams().get("AILogic"));
//AbilityFactoryAttach.handleUnattachAura(cardToUnattach, c, gainControl);
} else if (cardToUnattach.isEquipment()) {
if (cardToUnattach.isEquipping() && c.getEquippedBy().contains(cardToUnattach)) {
cardToUnattach.unEquipCard(cardToUnattach.getEquipping().get(0));
}
//TODO - unfortify would also be handled here
}
} else if (o instanceof Player) {
final Player p = (Player) o;
if (cardToUnattach.isAura() && p.getEnchantedBy().contains(cardToUnattach)) {
//AbilityFactoryAttach.handleUnattachAura(cardToUnattach, p, false);
}
}
}
/* this isn't modifed to handled unattach yet, but should be for things like Remove Enchantments, etc.
private static void handleUnattachAura(final Card card, final GameEntity tgt, final boolean gainControl) {
if (card.isEnchanting()) {
// If this Card is already Enchanting something
// Need to unenchant it, then clear out the commands
final GameEntity oldEnchanted = card.getEnchanting();
card.removeEnchanting(oldEnchanted);
card.clearEnchantCommand();
card.clearUnEnchantCommand();
card.clearTriggers(); // not sure if cleartriggers is needed?
}
if (gainControl) {
// Handle GainControl Auras
final Player[] pl = new Player[1];
if (tgt instanceof Card) {
pl[0] = ((Card) tgt).getController();
} else {
pl[0] = (Player) tgt;
}
final Command onEnchant = new Command() {
private static final long serialVersionUID = -2519887209491512000L;
@Override
public void execute() {
final Card crd = card.getEnchantingCard();
if (crd == null) {
return;
}
pl[0] = crd.getController();
crd.addController(card);
} // execute()
}; // Command
final Command onUnEnchant = new Command() {
private static final long serialVersionUID = 3426441132121179288L;
@Override
public void execute() {
final Card crd = card.getEnchantingCard();
if (crd == null) {
return;
}
if (AllZoneUtil.isCardInPlay(crd)) {
crd.removeController(card);
}
} // execute()
}; // Command
final Command onChangesControl = new Command() {
private static final long serialVersionUID = -65903786170234039L;
@Override
public void execute() {
final Card crd = card.getEnchantingCard();
if (crd == null) {
return;
}
crd.removeController(card); // This looks odd, but will
// simply refresh controller
crd.addController(card);
} // execute()
}; // Command
// Add Enchant Commands for Control changers
card.addEnchantCommand(onEnchant);
card.addUnEnchantCommand(onUnEnchant);
card.addChangeControllerCommand(onChangesControl);
}
final Command onLeavesPlay = new Command() {
private static final long serialVersionUID = -639204333673364477L;
@Override
public void execute() {
final GameEntity entity = card.getEnchanting();
if (entity == null) {
return;
}
card.unEnchantEntity(entity);
}
}; // Command
card.addLeavesPlayCommand(onLeavesPlay);
card.enchantEntity(tgt);
}
*/
/* (non-Javadoc)
* @see forge.card.abilityfactory.SpellEffect#getStackDescription(java.util.Map, forge.card.spellability.SpellAbility)
*/
@Override
protected String getStackDescription(Map<String, String> params, SpellAbility sa) {
final StringBuilder sb = new StringBuilder();
sb.append("Unattach all valid Equipment and Auras from ");
final List<Object> targets = getTargetObjects(sa, params);
sb.append(StringUtils.join(targets, " "));
return sb.toString();
}
/* (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) {
Card source = sa.getSourceCard();
final Target tgt = sa.getTarget();
final List<Object> targets = getTargetObjects(sa, params);
// If Cast Targets will be checked on the Stack
for (final Object o : targets) {
if (!( o instanceof GameEntity )) continue;
String valid = params.get("UnattachValid");
List<Card> unattachList = Singletons.getModel().getGame().getCardsIn(ZoneType.Battlefield);
unattachList = CardLists.getValidCards(unattachList, valid.split(","), source.getController(), source);
for (final Card c : unattachList) {
handleUnattachment((GameEntity)o, c);
}
}
}
}