merge latest trunk

This commit is contained in:
myk
2013-03-17 00:23:16 +00:00
71 changed files with 481 additions and 903 deletions

View File

@@ -198,7 +198,9 @@ public class Card extends GameEntity implements Comparable<Card> {
private String colorsPaid = "";
private Player owner = null;
private ArrayList<Object> controllerObjects = new ArrayList<Object>();
private Player controller = null;
private long controllerTimestamp = 0;
private TreeMap<Long, Player> tempControllers = new TreeMap<Long, Player>();
// private String rarity = "";
private String text = "";
@@ -3518,6 +3520,13 @@ public class Card extends GameEntity implements Comparable<Card> {
public final void addChangeControllerCommand(final Command c) {
this.changeControllerCommandList.add(c);
}
public final void runChangeControllerCommands() {
for (final Command c : this.changeControllerCommandList) {
c.execute();
}
}
/**
* <p>
@@ -3574,98 +3583,41 @@ public class Card extends GameEntity implements Comparable<Card> {
* @return a {@link forge.game.player.Player} object.
*/
public final Player getController() {
if (this.controllerObjects.size() == 0) {
return this.owner;
if (!this.tempControllers.isEmpty()) {
final long lastTimestamp = this.tempControllers.lastKey();
if (lastTimestamp > this.controllerTimestamp) {
return this.tempControllers.lastEntry().getValue();
}
}
final Object topController = this.controllerObjects.get(this.controllerObjects.size() - 1);
if (topController instanceof Player) {
return (Player) topController;
if (this.controller != null) {
return this.controller;
}
return ((Card) topController).getController();
return this.owner;
}
/**
*
* TODO Write javadoc for this method.
*
* @param controllerObject
* an Object
*/
public final void addController(final Object controllerObject) {
final Object prevController = this.controllerObjects.size() == 0 ? this.owner : this.controllerObjects
.get(this.controllerObjects.size() - 1);
if (!controllerObject.equals(prevController)) {
if (controllerObject instanceof Player) {
for (int i = 0; i < this.controllerObjects.size(); i++) {
if (this.controllerObjects.get(i) instanceof Player) {
this.controllerObjects.remove(i);
}
}
}
this.controllerObjects.add(controllerObject);
if ((Singletons.getModel().getGame().getAction() != null) && (prevController != null)) {
Singletons.getModel().getGame().getAction().controllerChangeZoneCorrection(this);
}
if (prevController != null) {
for (final Command c : this.changeControllerCommandList) {
c.execute();
}
}
this.updateObservers();
}
public final void addTempController(final Player player, final long tstamp) {
this.tempControllers.put(tstamp, player);
}
/**
*
* TODO Write javadoc for this method.
*
* @param controllerObject
* a Object
*/
public final void removeController(final Object controllerObject) {
final Object currentController = this.getController();
this.controllerObjects.remove(controllerObject);
if (!currentController.equals(this.getController())) {
Singletons.getModel().getGame().getAction().controllerChangeZoneCorrection(this);
for (final Command c : this.changeControllerCommandList) {
c.execute();
}
this.updateObservers();
}
public final void removeTempController(final long tstamp) {
this.tempControllers.remove(tstamp);
}
public final void clearTempControllers() {
this.tempControllers.clear();
}
/**
*
* TODO Write javadoc for this method.
*/
public final void clearControllers() {
this.controllerObjects.clear();
clearTempControllers();
this.controller = null;
}
/**
*
* TODO Write javadoc for this method.
*
* @return an ArrayList<Object>
*/
public final ArrayList<Object> getControllerObjects() {
return this.controllerObjects;
}
/**
*
* TODO Write javadoc for this method.
*
* @param in
* an Object
*/
public final void setControllerObjects(final ArrayList<Object> in) {
this.controllerObjects = in;
public final void setController(final Player player, final long tstamp) {
clearTempControllers();
this.controller = player;
this.controllerTimestamp = tstamp;
}
/**
@@ -3678,23 +3630,8 @@ public class Card extends GameEntity implements Comparable<Card> {
*/
public final void setOwner(final Player player) {
this.owner = player;
//this.updateObservers();
}
/**
* <p>
* Setter for the field <code>controller</code>.
* </p>
*
* @return the equipped by
*/
/*
* public void setController(Player player) { boolean sameController =
* controller == null ? false : controller.isPlayer(player); controller =
* player; if (null != controller && !sameController) { for (Command var :
* changeControllerCommandList) var.execute(); } this.updateObservers(); }
*/
/**
* <p>
* Getter for the field <code>equippedBy</code>.

View File

@@ -24,6 +24,7 @@ import java.util.List;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
@@ -89,6 +90,8 @@ public class CardLists {
return aLen - bLen;
}
};
public static final List<Card> emptyList = ImmutableList.of();
/**
* <p>

View File

@@ -136,6 +136,7 @@ public final class CardUtil {
newCopy.setUniqueNumber(in.getUniqueNumber());
newCopy.setCurSetCode(in.getCurSetCode());
newCopy.setOwner(in.getOwner());
newCopy.setController(in.getController(), 0);
newCopy.setFlipCard(in.isFlipCard());
newCopy.setDoubleFaced(in.isDoubleFaced());
newCopy.getCharacteristics().copy(in.getState(in.getCurState()));
@@ -148,7 +149,6 @@ public final class CardUtil {
sa.setSourceCard(in);
}
newCopy.setControllerObjects(in.getControllerObjects());
newCopy.setCounters(in.getCounters());
newCopy.setExtrinsicKeyword(in.getExtrinsicKeyword());
newCopy.setColor(in.getColor());

View File

@@ -184,6 +184,11 @@ public class StaticEffects {
// modify the affected card
for (int i = 0; i < affectedCards.size(); i++) {
final Card affectedCard = affectedCards.get(i);
// Gain control
if (params.containsKey("GainControl")) {
affectedCard.removeTempController(se.getTimestamp());
}
// remove set P/T
if (!params.containsKey("CharacteristicDefining") && setPT) {

View File

@@ -13,7 +13,6 @@ import com.google.common.base.Predicates;
import forge.Card;
import forge.CardLists;
import forge.CardPredicates;
import forge.CardPredicates.Presets;
import forge.CardUtil;
import forge.Singletons;
import forge.card.ability.AbilityUtils;

View File

@@ -1254,7 +1254,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
c.setTapped(true);
}
if (sa.hasParam("GainControl")) {
c.addController(sa.getSourceCard());
c.setController(sa.getActivatingPlayer(), Singletons.getModel().getGame().getNextTimestamp());
}
if (sa.hasParam("AttachedTo")) {

View File

@@ -81,6 +81,9 @@ public class DiscardAi extends SpellAbilityAi {
// Set PayX here to maximum value.
final int cardsToDiscard = Math.min(ComputerUtilMana.determineLeftoverMana(sa, ai), ai.getOpponent()
.getCardsIn(ZoneType.Hand).size());
if (cardsToDiscard < 1) {
return false;
}
source.setSVar("PayX", Integer.toString(cardsToDiscard));
} else {
if (AbilityUtils.calculateAmount(sa.getSourceCard(), sa.getParam("NumCards"), sa) < 1) {

View File

@@ -30,7 +30,7 @@ public class AttachEffect extends SpellAbilityEffect {
// The Spell_Permanent (Auras) version of this AF needs to
// move the card into play before Attaching
sa.getSourceCard().addController(sa.getActivatingPlayer());
sa.getSourceCard().setController(sa.getActivatingPlayer(), 0);
final Card c = Singletons.getModel().getGame().getAction().moveTo(sa.getActivatingPlayer().getZone(ZoneType.Battlefield), sa.getSourceCard());
sa.setSourceCard(c);
}
@@ -93,8 +93,7 @@ public class AttachEffect extends SpellAbilityEffect {
// Spellweaver Volute, Dance of the Dead, Animate Dead
// Although honestly, I'm not sure if the three of those could
// handle being scripted
final boolean gainControl = "GainControl".equals(sa.getParam("AILogic"));
handleAura(card, c, gainControl);
handleAura(card, c);
} else if (card.isEquipment()) {
card.equipCard(c);
// else if (card.isFortification())
@@ -106,7 +105,7 @@ public class AttachEffect extends SpellAbilityEffect {
// Curse cards
final Player p = (Player) o;
if (card.isAura()) {
handleAura(card, p, false);
handleAura(card, p);
}
}
}
@@ -121,7 +120,7 @@ public class AttachEffect extends SpellAbilityEffect {
* @param gainControl
* the gain control
*/
public static void handleAura(final Card card, final GameEntity tgt, final boolean gainControl) {
public static void handleAura(final Card card, final GameEntity tgt) {
if (card.isEnchanting()) {
// If this Card is already Enchanting something
// Need to unenchant it, then clear out the commands
@@ -133,72 +132,6 @@ public class AttachEffect extends SpellAbilityEffect {
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 (crd.isInPlay()) {
crd.removeController(card);
}
} // execute()
}; // Command
final Command onChangesControl = new Command() {
/** automatically generated serialVersionUID. */
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;
@@ -252,7 +185,6 @@ public class AttachEffect extends SpellAbilityEffect {
}
aura.setActivatingPlayer(source.getController());
final Target tgt = aura.getTarget();
final boolean gainControl = "GainControl".equals(aura.getParam("AILogic"));
if (source.getController().isHuman()) {
if (tgt.canTgtPlayer()) {
@@ -266,8 +198,7 @@ public class AttachEffect extends SpellAbilityEffect {
final Player p = GuiChoose.one(source + " - Select a player to attach to.", players);
if (p != null) {
handleAura(source, p, false);
//source.enchantEntity((Player) o);
handleAura(source, p);
return true;
}
} else {
@@ -279,7 +210,7 @@ public class AttachEffect extends SpellAbilityEffect {
final Object o = GuiChoose.one(source + " - Select a card to attach to.", list);
if (o instanceof Card) {
handleAura(source, (Card) o, gainControl);
handleAura(source, (Card) o);
//source.enchantEntity((Card) o);
return true;
}
@@ -290,11 +221,11 @@ public class AttachEffect extends SpellAbilityEffect {
final Object o = aura.getTarget().getTargets().get(0);
if (o instanceof Card) {
//source.enchantEntity((Card) o);
handleAura(source, (Card) o, gainControl);
handleAura(source, (Card) o);
return true;
} else if (o instanceof Player) {
//source.enchantEntity((Player) o);
handleAura(source, (Player) o, false);
handleAura(source, (Player) o);
return true;
}
}

View File

@@ -81,7 +81,7 @@ public class ChangeZoneAllEffect extends SpellAbilityEffect {
}
if (sa.hasParam("GainControl")) {
c.addController(sa.getSourceCard());
c.setController(sa.getActivatingPlayer(), Singletons.getModel().getGame().getNextTimestamp());
Singletons.getModel().getGame().getAction().moveToPlay(c, sa.getActivatingPlayer());
} else {
final Card movedCard = Singletons.getModel().getGame().getAction().moveTo(destination, c, libraryPos);

View File

@@ -386,7 +386,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
tgtC.setTapped(true);
}
if (sa.hasParam("GainControl")) {
tgtC.addController(sa.getSourceCard());
tgtC.setController(sa.getActivatingPlayer(), Singletons.getModel().getGame().getNextTimestamp());
}
if (sa.hasParam("AttachedTo")) {
List<Card> list = AbilityUtils.getDefinedCards(hostCard,
@@ -670,7 +670,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
c.setTapped(true);
}
if (sa.hasParam("GainControl")) {
c.addController(sa.getSourceCard());
c.setController(sa.getActivatingPlayer(), Singletons.getModel().getGame().getNextTimestamp());
}
if (sa.hasParam("AttachedTo")) {

View File

@@ -3,6 +3,7 @@ package forge.card.ability.effects;
import java.util.ArrayList;
import forge.Card;
import forge.Singletons;
import forge.card.ability.AbilityUtils;
import forge.card.ability.SpellAbilityEffect;
import forge.card.spellability.SpellAbility;
@@ -56,9 +57,10 @@ public class ControlExchangeEffect extends SpellAbilityEffect {
return;
}
Player player2 = object2.getController();
object2.addController(object1.getController());
object1.addController(player2);
final Player player2 = object2.getController();
final long tStamp = Singletons.getModel().getGame().getNextTimestamp();
object2.setController(object1.getController(), tStamp);
object1.setController(player2, tStamp);
}
}

View File

@@ -6,7 +6,6 @@ import java.util.List;
import forge.Card;
import forge.Command;
import forge.GameEntity;
import forge.Singletons;
import forge.card.ability.AbilityUtils;
import forge.card.ability.SpellAbilityEffect;
@@ -52,14 +51,12 @@ public class ControlGainEffect extends SpellAbilityEffect {
}
private void doLoseControl(final Card c, final Card host, final boolean tapOnLose,
final List<String> addedKeywords, final GameEntity newController) {
final List<String> addedKeywords, final long tStamp) {
if (null == c) {
return;
}
if (c.isInPlay()) {
c.removeController(newController);
// Singletons.getModel().getGameAction().changeController(new ArrayList<Card>(c),
// c.getController(), originalController);
c.removeTempController(tStamp);
if (tapOnLose) {
c.tap();
@@ -105,14 +102,10 @@ public class ControlGainEffect extends SpellAbilityEffect {
controllers = tgt.getTargetPlayers();
}
GameEntity newController;
Player newController;
if (controllers.size() == 0) {
if (sa.isSpell()) {
newController = sa.getActivatingPlayer();
} else {
newController = source;
}
newController = sa.getActivatingPlayer();
} else {
newController = controllers.get(0);
}
@@ -124,66 +117,62 @@ public class ControlGainEffect extends SpellAbilityEffect {
return;
}
final int size = tgtCards.size();
for (int j = 0; j < size; j++) {
final Card tgtC = tgtCards.get(j);
final Player originalController = tgtC.getController();
for (Card tgtC : tgtCards) {
if (!tgtC.equals(sa.getSourceCard()) && !sa.getSourceCard().getGainControlTargets().contains(tgtC)) {
sa.getSourceCard().addGainControlTarget(tgtC);
}
if (tgtC.isInPlay()) {
if (!tgtC.isInPlay()) {
return;
}
if (!tgtC.equals(newController)) {
tgtC.addController(newController);
}
// Singletons.getModel().getGameAction().changeController(new ArrayList<Card>(tgtC),
// tgtC.getController(), newController.get(0));
long tStamp = Singletons.getModel().getGame().getNextTimestamp();
if (lose != null) {
tgtC.addTempController(newController, tStamp);
} else {
tgtC.setController(newController, tStamp);
}
if (bUntap) {
tgtC.untap();
}
if (bUntap) {
tgtC.untap();
}
if (null != kws) {
for (final String kw : kws) {
tgtC.addExtrinsicKeyword(kw);
}
if (null != kws) {
for (final String kw : kws) {
tgtC.addExtrinsicKeyword(kw);
}
}
// end copied
final Card hostCard = sa.getSourceCard();
if (lose != null) {
if (lose.contains("LeavesPlay")) {
sa.getSourceCard().addLeavesPlayCommand(this.getLoseControlCommand(tgtC, originalController, newController, bTapOnLose, hostCard, kws));
sa.getSourceCard().addLeavesPlayCommand(this.getLoseControlCommand(tgtC, tStamp, bTapOnLose, source, kws));
}
if (lose.contains("Untap")) {
sa.getSourceCard().addUntapCommand(this.getLoseControlCommand(tgtC, originalController, newController, bTapOnLose, hostCard, kws));
sa.getSourceCard().addUntapCommand(this.getLoseControlCommand(tgtC, tStamp, bTapOnLose, source, kws));
}
if (lose.contains("LoseControl")) {
sa.getSourceCard().addChangeControllerCommand(this.getLoseControlCommand(tgtC, originalController, newController, bTapOnLose, hostCard, kws));
sa.getSourceCard().addChangeControllerCommand(this.getLoseControlCommand(tgtC, tStamp, bTapOnLose, source, kws));
}
if (lose.contains("EOT")) {
Singletons.getModel().getGame().getEndOfTurn().addAt(this.getLoseControlCommand(tgtC, originalController, newController, bTapOnLose, hostCard, kws));
Singletons.getModel().getGame().getEndOfTurn().addAt(this.getLoseControlCommand(tgtC, tStamp, bTapOnLose, source, kws));
}
}
if (destroyOn != null) {
if (destroyOn.contains("LeavesPlay")) {
sa.getSourceCard().addLeavesPlayCommand(this.getDestroyCommand(tgtC, hostCard, bNoRegen));
sa.getSourceCard().addLeavesPlayCommand(this.getDestroyCommand(tgtC, source, bNoRegen));
}
if (destroyOn.contains("Untap")) {
sa.getSourceCard().addUntapCommand(this.getDestroyCommand(tgtC, hostCard, bNoRegen));
sa.getSourceCard().addUntapCommand(this.getDestroyCommand(tgtC, source, bNoRegen));
}
if (destroyOn.contains("LoseControl")) {
sa.getSourceCard().addChangeControllerCommand(this.getDestroyCommand(tgtC, hostCard, bNoRegen));
sa.getSourceCard().addChangeControllerCommand(this.getDestroyCommand(tgtC, source, bNoRegen));
}
}
sa.getSourceCard().clearGainControlReleaseCommands();
sa.getSourceCard().addGainControlReleaseCommand(this.getLoseControlCommand(tgtC, originalController, newController, bTapOnLose, hostCard, kws));
sa.getSourceCard().addGainControlReleaseCommand(this.getLoseControlCommand(tgtC, tStamp, bTapOnLose, source, kws));
} // end foreach target
}
@@ -239,13 +228,13 @@ public class ControlGainEffect extends SpellAbilityEffect {
* a {@link forge.game.player.Player} object.
* @return a {@link forge.Command} object.
*/
private Command getLoseControlCommand(final Card c, final Player originalController, final GameEntity newController,
private Command getLoseControlCommand(final Card c, final long tStamp,
final boolean bTapOnLose, final Card hostCard, final List<String> kws) {
final Command loseControl = new Command() {
private static final long serialVersionUID = 878543373519872418L;
@Override
public void execute() { doLoseControl(c, hostCard, bTapOnLose, kws, newController); } // execute()
public void execute() { doLoseControl(c, hostCard, bTapOnLose, kws, tStamp); }
};
return loseControl;

View File

@@ -86,7 +86,7 @@ public class CopyPermanentEffect extends SpellAbilityEffect {
copy = CardFactory.getCard(CardDb.getCard(c), sa.getActivatingPlayer());
// when copying something stolen:
copy.addController(controller);
copy.setController(controller, 0);
copy.setToken(true);
copy.setCopiedToken(true);
@@ -97,7 +97,7 @@ public class CopyPermanentEffect extends SpellAbilityEffect {
copy.setImageKey(c.getImageKey());
copy.setOwner(controller);
copy.addController(controller);
copy.setController(controller, 0);
copy.setManaCost(c.getManaCost());
copy.setColor(c.getColor());

View File

@@ -149,11 +149,11 @@ public class CounterEffect extends SpellAbilityEffect {
if (tgtSA instanceof SpellPermanent) {
Card c = tgtSA.getSourceCard();
System.out.println(c + " is SpellPermanent");
c.addController(srcSA.getActivatingPlayer());
c.setController(srcSA.getActivatingPlayer(), 0);
Singletons.getModel().getGame().getAction().moveToPlay(c, srcSA.getActivatingPlayer());
} else {
Card c = Singletons.getModel().getGame().getAction().moveToPlay(tgtSA.getSourceCard(), srcSA.getActivatingPlayer());
c.addController(srcSA.getActivatingPlayer());
c.setController(srcSA.getActivatingPlayer(), 0);
}
} else if (destination.equals("BottomOfLibrary")) {
Singletons.getModel().getGame().getAction().moveToBottomOfLibrary(tgtSA.getSourceCard());

View File

@@ -131,7 +131,7 @@ public class DigUntilEffect extends SpellAbilityEffect {
while (itr.hasNext()) {
final Card c = itr.next();
if (sa.hasParam("GainControl") && foundDest.equals(ZoneType.Battlefield)) {
c.addController(sa.getSourceCard());
c.setController(sa.getActivatingPlayer(), Singletons.getModel().getGame().getNextTimestamp());
Singletons.getModel().getGame().getAction().moveTo(c.getController().getZone(foundDest), c);
} else if (sa.hasParam("NoMoveFound") && foundDest.equals(ZoneType.Library)) {
//Don't do anything

View File

@@ -1,26 +1,18 @@
package forge.card.ability.effects;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import com.google.common.base.Predicate;
import forge.Card;
import forge.CardLists;
import forge.card.ability.AbilityUtils;
import forge.card.cardfactory.CardFactoryUtil;
import forge.card.spellability.SpellAbility;
import forge.card.spellability.Target;
import forge.game.ai.ComputerUtilCard;
import forge.game.player.AIPlayer;
import forge.game.player.Player;
import forge.game.zone.ZoneType;
import forge.gui.GuiChoose;
import forge.util.Aggregates;
public class DiscardEffect extends RevealEffectBase {
@Override
@@ -87,44 +79,6 @@ public class DiscardEffect extends RevealEffectBase {
return sb.toString();
} // discardStackDescription()
/**
* TODO: Write javadoc for this method.
* @param sa
* @param opponentHand
* @param list
*/
private Card chooseCardToDiscardFromOpponent(SpellAbility sa, List<Card> opponentHand) {
List<Card> goodChoices = CardLists.filter(opponentHand, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
if (!c.getSVar("DiscardMeByOpp").equals("") || !c.getSVar("DiscardMe").equals("")) {
return false;
}
return true;
}
});
if (goodChoices.isEmpty()) {
goodChoices = opponentHand;
}
final List<Card> dChoices = new ArrayList<Card>();
if (sa.hasParam("DiscardValid")) {
final String validString = sa.getParam("DiscardValid");
if (validString.contains("Creature") && !validString.contains("nonCreature")) {
final Card c = ComputerUtilCard.getBestCreatureAI(goodChoices);
if (c != null) {
dChoices.add(ComputerUtilCard.getBestCreatureAI(goodChoices));
}
}
}
Collections.sort(goodChoices, CardLists.TextLenComparator);
CardLists.sortByCmcDesc(goodChoices);
dChoices.add(goodChoices.get(0));
return Aggregates.random(goodChoices);
}
@Override
public void resolve(SpellAbility sa) {
final Card source = sa.getSourceCard();
@@ -194,11 +148,7 @@ public class DiscardEffect extends RevealEffectBase {
// Reveal
final List<Card> dPHand = p.getCardsIn(ZoneType.Hand);
if (p.isHuman()) {
// "reveal to computer" for information gathering
} else {
GuiChoose.oneOrNone("Revealed computer hand", dPHand);
}
p.getOpponent().getController().reveal("Reveal " + p + " hand" , dPHand, ZoneType.Hand, p);
String valid = sa.hasParam("DiscardValid") ? sa.getParam("DiscardValid") : "Card";
@@ -215,7 +165,7 @@ public class DiscardEffect extends RevealEffectBase {
} else if (mode.equals("RevealYouChoose") || mode.equals("RevealOppChoose") || mode.equals("TgtChoose")) {
// Is Reveal you choose right? I think the wrong player is
// being used?
List<Card> dPHand = new ArrayList<Card>(p.getCardsIn(ZoneType.Hand));
List<Card> dPHand = p.getCardsIn(ZoneType.Hand);
if (dPHand.isEmpty())
continue; // for loop over players
@@ -224,11 +174,9 @@ public class DiscardEffect extends RevealEffectBase {
int amount = StringUtils.isNumeric(amountString) ? Integer.parseInt(amountString) : CardFactoryUtil.xCount(source, source.getSVar(amountString));
dPHand = getRevealedList(p, dPHand, amount, false);
}
List<Card> dPChHand = new ArrayList<Card>(dPHand);
final String valid = sa.hasParam("DiscardValid") ? sa.getParam("DiscardValid") : "Card";
String[] dValid = ArrayUtils.EMPTY_STRING_ARRAY;
dValid = valid.split(",");
dPChHand = CardLists.getValidCards(dPHand, dValid, source.getController(), source);
String[] dValid = valid.split(",");
List<Card> validCards = CardLists.getValidCards(dPHand, dValid, source.getController(), source);
Player chooser = p;
if (mode.equals("RevealYouChoose")) {
@@ -237,60 +185,16 @@ public class DiscardEffect extends RevealEffectBase {
chooser = source.getController().getOpponent();
}
List<Card> toBeDiscarded = new ArrayList<Card>();
if (chooser.isComputer()) {
List<Card> dPChHand1 = new ArrayList<Card>(p.getCardsIn(ZoneType.Hand));
dPChHand1 = CardLists.getValidCards(dPChHand1, dValid, source.getController(), source);
int max = Math.min(dPChHand1.size(), numCards);
List<Card> list = new ArrayList<Card>();
if (!p.isOpponentOf(chooser) && p instanceof AIPlayer) { // discard AI cards
toBeDiscarded = ((AIPlayer) p).getAi().getCardsToDiscard(max, dValid, sa);
} else {
// discard hostile or human opponent
for (int i = 0; i < max; i++) {
Card dC = chooseCardToDiscardFromOpponent(sa, dPChHand1);
dPChHand1.remove(dC);
toBeDiscarded.add(dC);
}
}
if (mode.startsWith("Reveal")) {
GuiChoose.oneOrNone("Computer has chosen", list);
}
if (mode.startsWith("Reveal") && p != chooser)
chooser.getController().reveal("Revealed " + p + " hand", dPHand, ZoneType.Hand, p);
int minDiscardAmount = sa.hasParam("AnyNumber") || sa.hasParam("Optional") ? 0 : numCards;
int max = Math.min(validCards.size(), minDiscardAmount);
} else {
// human
if (mode.startsWith("Reveal")) {
GuiChoose.oneOrNone("Revealed " + p + " hand", dPHand);
}
List<Card> toBeDiscarded = validCards.isEmpty() ? CardLists.emptyList : chooser.getController().chooseCardsToDiscardFrom(p, sa, validCards, max);
if (sa.hasParam("AnyNumber")) {
List<Card> chosen = getDiscardedList(p, dPChHand);
for (Card c : chosen) {
dPChHand.remove(c);
toBeDiscarded.add(c);
}
} else
for (int i = 0; i < numCards; i++) {
if (dPChHand.isEmpty()) {
break;
}
Card dC = null;
if (sa.hasParam("Optional")) {
dC = GuiChoose.oneOrNone("Choose a card to be discarded", dPChHand);
} else {
dC = GuiChoose.one("Choose a card to be discarded", dPChHand);
}
if (dC != null) {
dPChHand.remove(dC);
toBeDiscarded.add(dC);
}
else break;
}
if (mode.startsWith("Reveal") ) {
p.getController().reveal(chooser + " has chosen", toBeDiscarded, ZoneType.Hand, p);
}
if (toBeDiscarded != null) {
@@ -311,34 +215,4 @@ public class DiscardEffect extends RevealEffectBase {
}
} // discardResolve()
public static List<Card> getDiscardedList(final Player player, final List<Card> valid) {
final List<Card> chosen = new ArrayList<Card>();
final int validamount = Math.min(valid.size(), valid.size());
if (player.isHuman() && validamount > 0) {
final List<Card> selection = GuiChoose.order("Choose Which Cards to Discard", "Discarded", -1, valid, null, null);
for (final Object o : selection) {
if (o != null && o instanceof Card) {
chosen.add((Card) o);
}
}
} else {
for (int i = 0; i < validamount; i++) {
if (player.isHuman()) {
final Card o = GuiChoose.one("Choose card(s) to discard", valid);
if (o != null) {
chosen.add(o);
valid.remove(o);
} else {
break;
}
} else { // Computer
chosen.add(valid.get(0));
valid.remove(valid.get(0));
}
}
}
return chosen;
}
}

View File

@@ -17,7 +17,7 @@ public class PermanentCreatureEfect extends SpellAbilityEffect {
*/
@Override
public void resolve(SpellAbility sa) {
sa.getSourceCard().addController(sa.getActivatingPlayer());
sa.getSourceCard().setController(sa.getActivatingPlayer(), 0);
final Card c = Singletons.getModel().getGame().getAction().moveTo(sa.getActivatingPlayer().getZone(ZoneType.Battlefield), sa.getSourceCard());
sa.setSourceCard(c);
}

View File

@@ -17,7 +17,7 @@ public class PermanentNoncreatureEffect extends SpellAbilityEffect {
*/
@Override
public void resolve(SpellAbility sa) {
sa.getSourceCard().addController(sa.getActivatingPlayer());
sa.getSourceCard().setController(sa.getActivatingPlayer(), 0);
final Card c = Singletons.getModel().getGame().getAction().moveTo(sa.getActivatingPlayer().getZone(ZoneType.Battlefield), sa.getSourceCard());
sa.setSourceCard(c);
}

View File

@@ -462,22 +462,13 @@ public class CardFactorySorceries {
}
private static final void balanceHands(Spell card) {
List<List<Card>> hands = new ArrayList<List<Card>>();
for (Player p : Singletons.getModel().getGame().getPlayers()) {
hands.add(p.getCardsIn(ZoneType.Hand));
}
int min = Integer.MAX_VALUE;
for (List<Card> h : hands) {
int s = h.size();
min = Math.min(min, s);
}
Iterator<List<Card>> hh = hands.iterator();
for (Player p : Singletons.getModel().getGame().getPlayers()) {
min = Math.min(min, p.getZone(ZoneType.Hand).size());
}
List<Card> h = hh.next();
int sac = h.size() - min;
for (Player p : Singletons.getModel().getGame().getPlayers()) {
int sac = p.getCardsIn(ZoneType.Hand).size() - min;
if (sac == 0) {
continue;
}

View File

@@ -574,7 +574,7 @@ public class SpellPermanent extends Spell {
@Override
public void resolve() {
Card c = this.getSourceCard();
c.addController(this.getActivatingPlayer());
c.setController(this.getActivatingPlayer(), 0);
Singletons.getModel().getGame().getAction().moveTo(ZoneType.Battlefield, c);
}
}

View File

@@ -137,6 +137,10 @@ public class StaticAbility {
return 0;
}
if (this.params.containsKey("GainControl")) {
return 2;
}
if (this.params.containsKey("AddType") || this.params.containsKey("RemoveType")
|| this.params.containsKey("RemoveCardType") || this.params.containsKey("RemoveSubType")
|| this.params.containsKey("RemoveSuperType")) {

View File

@@ -317,6 +317,11 @@ public class StaticAbilityContinuous {
// start modifying the cards
for (int i = 0; i < affectedCards.size(); i++) {
final Card affectedCard = affectedCards.get(i);
// Gain control
if (params.containsKey("GainControl")) {
affectedCard.addTempController(hostCard.getController(), hostCard.getTimestamp());
}
// set P/T
if (params.containsKey("CharacteristicDefining")) {

View File

@@ -977,9 +977,18 @@ public class GameAction {
final HashMap<String, Object> runParams = new HashMap<String, Object>();
game.getTriggerHandler().runTrigger(TriggerType.Always, runParams, false);
for (Player p : game.getPlayers()) {
for (Card c : p.getCardsIn(ZoneType.Battlefield)) {
if (!c.getController().equals(p)) {
controllerChangeZoneCorrection(c);
c.runChangeControllerCommands();
checkAgain = true;
}
}
}
for (Card c : game.getCardsIn(ZoneType.Battlefield)) {
if (c.isEquipped()) {
final List<Card> equipments = new ArrayList<Card>(c.getEquippedBy());
for (final Card equipment : equipments) {
@@ -990,7 +999,6 @@ public class GameAction {
}
} // if isEquipped()
if (c.isEquipping()) {
final Card equippedCreature = c.getEquipping().get(0);
if (!equippedCreature.isCreature() || !equippedCreature.isInPlay()) {
@@ -1091,7 +1099,7 @@ public class GameAction {
checkAgain = true;
}
} // while it.hasNext()
}
if (game.getTriggerHandler().runWaitingTriggers(true)) {
checkAgain = true;

View File

@@ -47,6 +47,7 @@ import forge.game.player.Player;
import forge.game.zone.ZoneType;
import forge.util.Aggregates;
import forge.util.Expressions;
import forge.util.MyRandom;
/**
* <p>
@@ -524,16 +525,21 @@ public class AiController {
*/
public List<Card> getCardsToDiscard(final int numDiscard, final String[] uTypes, final SpellAbility sa) {
List<Card> hand = new ArrayList<Card>(player.getCardsIn(ZoneType.Hand));
Card sourceCard = null;
if ((uTypes != null) && (sa != null)) {
hand = CardLists.getValidCards(hand, uTypes, sa.getActivatingPlayer(), sa.getSourceCard());
}
return getCardsToDiscard(numDiscard, hand, sa);
}
if (hand.size() < numDiscard) {
public List<Card> getCardsToDiscard(final int numDiscard, final List<Card> validCards, final SpellAbility sa) {
if (validCards.size() < numDiscard) {
return null;
}
Card sourceCard = null;
final List<Card> discardList = new ArrayList<Card>();
int count = 0;
if (sa != null) {
@@ -544,7 +550,7 @@ public class AiController {
while (count < numDiscard) {
Card prefCard = null;
if (sa != null && sa.getActivatingPlayer() != null && sa.getActivatingPlayer().isOpponentOf(player)) {
for (Card c : hand) {
for (Card c : validCards) {
if (c.hasKeyword("If a spell or ability an opponent controls causes you to discard CARDNAME,"
+ " put it onto the battlefield instead of putting it into your graveyard.")) {
prefCard = c;
@@ -553,11 +559,11 @@ public class AiController {
}
}
if (prefCard == null) {
prefCard = ComputerUtil.getCardPreference(player, sourceCard, "DiscardCost", hand);
prefCard = ComputerUtil.getCardPreference(player, sourceCard, "DiscardCost", validCards);
}
if (prefCard != null) {
discardList.add(prefCard);
hand.remove(prefCard);
validCards.remove(prefCard);
count++;
} else {
break;
@@ -568,11 +574,11 @@ public class AiController {
// choose rest
for (int i = 0; i < discardsLeft; i++) {
if (hand.isEmpty()) {
if (validCards.isEmpty()) {
continue;
}
final int numLandsInPlay = Iterables.size(Iterables.filter(player.getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.LANDS));
final List<Card> landsInHand = CardLists.filter(hand, CardPredicates.Presets.LANDS);
final List<Card> landsInHand = CardLists.filter(validCards, CardPredicates.Presets.LANDS);
final int numLandsInHand = landsInHand.size();
// Discard a land
@@ -581,21 +587,21 @@ public class AiController {
if (canDiscardLands) {
discardList.add(landsInHand.get(0));
hand.remove(landsInHand.get(0));
validCards.remove(landsInHand.get(0));
} else { // Discard other stuff
CardLists.sortByCmcDesc(hand);
CardLists.sortByCmcDesc(validCards);
int numLandsAvailable = numLandsInPlay;
if (numLandsInHand > 0) {
numLandsAvailable++;
}
//Discard unplayable card
if (hand.get(0).getCMC() > numLandsAvailable) {
discardList.add(hand.get(0));
hand.remove(hand.get(0));
if (validCards.get(0).getCMC() > numLandsAvailable) {
discardList.add(validCards.get(0));
validCards.remove(validCards.get(0));
} else { //Discard worst card
Card worst = ComputerUtilCard.getWorstAI(hand);
Card worst = ComputerUtilCard.getWorstAI(validCards);
discardList.add(worst);
hand.remove(worst);
validCards.remove(worst);
}
}
}
@@ -700,5 +706,18 @@ public class AiController {
}
return true;
}
/**
* AI decides if he wants to use dredge ability and which one if many available
* @param dredgers - contains at least single element
* @return
*/
public Card chooseCardToDredge(List<Card> dredgers) {
// use dredge if there are more than one of them in your graveyard
if (dredgers.size() > 1 || MyRandom.getRandom().nextBoolean()) {
return Aggregates.random(dredgers);
}
return null;
}
}

View File

@@ -87,8 +87,12 @@ public class AiInputCommon extends Input {
final int size = player.getCardsIn(ZoneType.Hand).size();
if (!player.isUnlimitedHandSize()) {
final int numDiscards = size - player.getMaxHandSize();
player.discard(numDiscards, null);
int max = Math.min(player.getZone(ZoneType.Hand).size(), size - player.getMaxHandSize());
final List<Card> toDiscard = player.getAi().getCardsToDiscard(max, (String[])null, null);
for (int i = 0; i < toDiscard.size(); i++) {
player.discard(toDiscard.get(i), null);
}
}
}
break;

View File

@@ -1000,21 +1000,7 @@ public class ComputerUtil {
for (final Card c : all) {
for (final SpellAbility sa : c.getSpellAbility()) {
if (sa.getApi() == null) {
continue;
}
/// ????
// if ( sa.isAbility() || sa.isSpell() && sa.getApi() != ApiType.Pump ) continue
if (sa.hasParam("AB") && !sa.getParam("AB").equals("Pump")) {
continue;
}
if (sa.hasParam("SP") && !sa.getParam("SP").equals("Pump")) {
continue;
}
if (sa.hasParam("KW") && sa.getParam("KW").contains("Haste")) {
if (sa.getApi() == ApiType.Pump && sa.hasParam("KW") && sa.getParam("KW").contains("Haste")) {
return true;
}
}
@@ -1238,4 +1224,62 @@ public class ComputerUtil {
}
return bottom;
}
/**
* TODO: Write javadoc for this method.
* @param chooser
* @param discarder
* @param sa
* @param validCards
* @param min
* @return
*/
public static List<Card> getCardsToDiscardFromOpponent(AIPlayer chooser, Player discarder, SpellAbility sa, List<Card> validCards, int min) {
List<Card> goodChoices = CardLists.filter(validCards, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
if (!c.getSVar("DiscardMeByOpp").equals("") || !c.getSVar("DiscardMe").equals("")) {
return false;
}
return true;
}
});
if (goodChoices.isEmpty()) {
goodChoices = validCards;
}
final List<Card> dChoices = new ArrayList<Card>();
if (sa.hasParam("DiscardValid")) {
final String validString = sa.getParam("DiscardValid");
if (validString.contains("Creature") && !validString.contains("nonCreature")) {
final Card c = ComputerUtilCard.getBestCreatureAI(goodChoices);
if (c != null) {
dChoices.add(ComputerUtilCard.getBestCreatureAI(goodChoices));
}
}
}
Collections.sort(goodChoices, CardLists.TextLenComparator);
CardLists.sortByCmcDesc(goodChoices);
dChoices.add(goodChoices.get(0));
return Aggregates.random(goodChoices, min);
}
/**
* TODO: Write javadoc for this method.
* @param aiChoser
* @param p
* @param sa
* @param validCards
* @param min
* @return
*/
public static List<Card> getCardsToDiscardFromFriend(AIPlayer aiChooser, Player p, SpellAbility sa, List<Card> validCards, int min) {
if (p instanceof AIPlayer) { // ask that ai player what he would like to discard
return ((AIPlayer) p).getAi().getCardsToDiscard(min, validCards, sa);
}
// no special options for human or remote friends
return getCardsToDiscardFromOpponent(aiChooser, p, sa, validCards, min);
}
}

View File

@@ -550,8 +550,7 @@ public class PhaseHandler extends MyObservable implements java.io.Serializable {
if (game.getType() == GameType.Planechase) {
Card p = game.getActivePlane();
if (p != null) {
p.clearControllers();
p.addController(next);
p.setController(next, 0);
game.getAction().controllerChangeZoneCorrection(p);
}
}

View File

@@ -18,8 +18,6 @@
package forge.game.player;
import java.util.List;
import java.util.Random;
import forge.Card;
import forge.CardLists;
@@ -27,10 +25,8 @@ import forge.CardPredicates;
import forge.card.spellability.SpellAbility;
import forge.game.GameState;
import forge.game.ai.AiController;
import forge.game.ai.ComputerUtilCard;
import forge.game.zone.ZoneType;
import forge.util.Aggregates;
import forge.util.MyRandom;
/**
* <p>
@@ -63,43 +59,6 @@ public class AIPlayer extends Player {
// //////////////////////////////
// /
// / replaces Singletons.getModel().getGameAction().draw* methods
// /
// //////////////////////////////
/**
* <p>
* dredge.
* </p>
*
* @return a boolean.
*/
@Override
public final boolean dredge() {
final List<Card> dredgers = this.getDredge();
final Random random = MyRandom.getRandom();
// use dredge if there are more than one of them in your graveyard
if ((dredgers.size() > 1) || ((dredgers.size() == 1) && random.nextBoolean())) {
CardLists.shuffle(dredgers);
final Card c = dredgers.get(0);
// rule 702.49a
if (this.getDredgeNumber(c) <= this.getCardsIn(ZoneType.Library).size()) {
// dredge library, put card in hand
game.getAction().moveToHand(c);
// put dredge number in graveyard
for (int i = 0; i < this.getDredgeNumber(c); i++) {
final Card c2 = this.getCardsIn(ZoneType.Library).get(0);
game.getAction().moveToGraveyard(c2);
}
return true;
}
}
return false;
}
// //////////////////////////////
// /
// / replaces Singletons.getModel().getGameAction().discard* methods
@@ -111,7 +70,7 @@ public class AIPlayer extends Player {
public final void discard(final int num, final SpellAbility sa) {
int max = this.getCardsIn(ZoneType.Hand).size();
max = Math.min(max, num);
final List<Card> toDiscard = this.getAi().getCardsToDiscard(max, null, sa);
final List<Card> toDiscard = this.getAi().getCardsToDiscard(max, (String[])null, sa);
for (int i = 0; i < toDiscard.size(); i++) {
this.doDiscard(toDiscard.get(i), sa);
}
@@ -125,8 +84,7 @@ public class AIPlayer extends Player {
if (tHand.size() > 0) {
Card toDiscard = Aggregates.itemWithMin(tHand, CardPredicates.Accessors.fnGetCmc);
toDiscard.getController().discard(toDiscard, sa); // this got changed
// to doDiscard basically
discard(toDiscard, sa); // this got changed to doDiscard basically
return;
}
this.discard(num, sa);
@@ -134,16 +92,6 @@ public class AIPlayer extends Player {
// /////////////////////////
/** {@inheritDoc} */
@Override
public final void sacrificePermanent(final String prompt, final List<Card> choices) {
if (choices.size() > 0) {
// TODO - this could probably use better AI
final Card c = ComputerUtilCard.getWorstPermanentAI(choices, false, false, false, false);
game.getAction().sacrificeDestroy(c);
}
}
/* (non-Javadoc)
* @see forge.game.player.Player#getType()
*/

View File

@@ -17,74 +17,19 @@
*/
package forge.game.player;
import java.util.List;
import forge.Card;
import forge.Singletons;
import forge.card.spellability.SpellAbility;
import forge.control.input.Input;
import forge.game.GameState;
import forge.game.zone.ZoneType;
import forge.gui.GuiChoose;
import forge.gui.GuiDialog;
/**
* <p>
* HumanPlayer class.
* </p>
*
* @author Forge
* @version $Id$
*/
public class HumanPlayer extends Player {
private PlayerControllerHuman controller;
/**
* <p>
* Constructor for HumanPlayer.
* </p>
*
* @param myName
* a {@link java.lang.String} object.
*/
public HumanPlayer(final LobbyPlayer player, GameState game) {
super(player, game);
controller = new PlayerControllerHuman(game, this);
}
/**
* <p>
* dredge.
* </p>
*
* @return a boolean.
*/
@Override
public final boolean dredge() {
boolean dredged = false;
final boolean wantDredge = GuiDialog.confirm(null, "Do you want to dredge?");
if (wantDredge) {
final Card c = GuiChoose.one("Select card to dredge", this.getDredge());
// rule 702.49a
if (this.getDredgeNumber(c) <= getZone(ZoneType.Library).size()) {
// might have to make this more sophisticated
// dredge library, put card in hand
game.getAction().moveToHand(c);
for (int i = 0; i < this.getDredgeNumber(c); i++) {
final Card c2 = getZone(ZoneType.Library).get(0);
game.getAction().moveToGraveyard(c2);
}
dredged = true;
} else {
dredged = false;
}
}
return dredged;
}
/** {@inheritDoc} */
@Override
public final void discard(final int num, final SpellAbility sa) {
@@ -99,26 +44,12 @@ public class HumanPlayer extends Player {
}
}
/** {@inheritDoc} */
@Override
public final void sacrificePermanent(final String prompt, final List<Card> choices) {
final Input in = PlayerUtil.inputSacrificePermanent(choices, prompt);
Singletons.getModel().getMatch().getInput().setInput(in);
}
/* (non-Javadoc)
* @see forge.game.player.Player#getType()
*/
@Override
public PlayerType getType() {
return PlayerType.HUMAN;
}
/* (non-Javadoc)
* @see forge.game.player.Player#getController()
*/
@Override
public PlayerController getController() {
return controller;
}
} // end HumanPlayer class

View File

@@ -1233,16 +1233,6 @@ public abstract class Player extends GameEntity implements Comparable<Player> {
return this.drawCards(1);
}
/**
* <p>
* dredge.
* </p>
*
* @return a boolean.
*/
public abstract boolean dredge();
/**
*
* TODO Write javadoc for this method.
@@ -1287,8 +1277,17 @@ public abstract class Player extends GameEntity implements Comparable<Player> {
for (int i = 0; i < n; i++) {
// TODO: multiple replacements need to be selected by the controller
if (!this.getDredge().isEmpty()) {
if (this.dredge()) {
List<Card> dredgers = this.getDredge();
if (!dredgers.isEmpty()) {
Card toDredge = getController().chooseCardToDredge(dredgers);
int dredgeNumber = toDredge == null ? Integer.MAX_VALUE : getDredgeNumber(toDredge);
if ( dredgeNumber <= getZone(ZoneType.Library).size()) {
game.getAction().moveToHand(toDredge);
for (int iD = 0; iD < dredgeNumber; iD++) {
final Card c2 = getZone(ZoneType.Library).get(0);
game.getAction().moveToGraveyard(c2);
}
continue;
}
}
@@ -1687,18 +1686,6 @@ public abstract class Player extends GameEntity implements Comparable<Player> {
return list;
}
/**
* <p>
* discardRandom.
* </p>
*
* @param sa
* a {@link forge.card.spellability.SpellAbility} object.
* @return a List<Card> of cards discarded
*/
public final List<Card> discardRandom(final SpellAbility sa) {
return this.discardRandom(1, sa);
}
/**
* <p>
@@ -1862,7 +1849,7 @@ public abstract class Player extends GameEntity implements Comparable<Player> {
*/
public final void playLand(final Card land) {
if (this.canPlayLand(land)) {
land.addController(this);
land.setController(this, 0);
game.getAction().moveTo(this.getZone(ZoneType.Battlefield), land);
CardFactoryUtil.playLandEffects(land);
this.numLandsPlayed++;
@@ -1910,9 +1897,7 @@ public abstract class Player extends GameEntity implements Comparable<Player> {
}
// Dev Mode
if (Singletons.getModel().getPreferences().getPrefBoolean(FPref.DEV_UNLIMITED_LAND)
&& this.isHuman()
&& Preferences.DEV_MODE) {
if (Singletons.getModel().getPreferences().getPrefBoolean(FPref.DEV_UNLIMITED_LAND) && this.getType() == PlayerType.HUMAN && Preferences.DEV_MODE) {
return true;
}
@@ -2140,19 +2125,6 @@ public abstract class Player extends GameEntity implements Comparable<Player> {
this.attackersDeclaredThisTurn = 0;
}
// //////////////////////////////
/**
* <p>
* sacrificePermanent.
* </p>
*
* @param prompt
* a {@link java.lang.String} object.
* @param choices
* a {@link forge.CardList} object.
*/
public abstract void sacrificePermanent(String prompt, List<Card> choices);
// Game win/loss
/**

View File

@@ -108,4 +108,8 @@ public abstract class PlayerController {
public abstract void reveal(String string, List<Card> cards, ZoneType zone, Player owner);
public abstract ImmutablePair<List<Card>, List<Card>> arrangeForScry(List<Card> topN);
public abstract boolean willPutCardOnTop(Card c);
/** p = target player, validCards - possible discards, min cards to discard */
public abstract List<Card> chooseCardsToDiscardFrom(Player p, SpellAbility sa, List<Card> validCards, int min);
public abstract Card chooseCardToDredge(List<Card> dredgers);
}

View File

@@ -255,4 +255,18 @@ public class PlayerControllerAi extends PlayerController {
return true; // AI does not know what will happen next (another clash or that would become his topdeck)
}
@Override
public List<Card> chooseCardsToDiscardFrom(Player p, SpellAbility sa, List<Card> validCards, int min) {
boolean isTargetFriendly = !p.isOpponentOf(getPlayer());
return isTargetFriendly
? ComputerUtil.getCardsToDiscardFromFriend(player, p, sa, validCards, min)
: ComputerUtil.getCardsToDiscardFromOpponent(player, p, sa, validCards, min);
}
@Override
public Card chooseCardToDredge(List<Card> dredgers) {
return brains.chooseCardToDredge(dredgers);
}
}

View File

@@ -318,4 +318,23 @@ public class PlayerControllerHuman extends PlayerController {
public boolean willPutCardOnTop(Card c) {
return GuiDialog.confirm(c, "Where will you put " + c.getName() + " in your library", new String[]{"Top", "Bottom"} );
}
/* (non-Javadoc)
* @see forge.game.player.PlayerController#chooseCardsToDiscardFrom(forge.game.player.Player, java.util.List, int)
*/
@Override
public List<Card> chooseCardsToDiscardFrom(Player p, SpellAbility sa, List<Card> valid, int minDiscard) {
return GuiChoose.order("Choose cards to Discard", "Discarded", minDiscard == 0 ? -1 : minDiscard, valid, null, null);
}
/* (non-Javadoc)
* @see forge.game.player.PlayerController#chooseCardToDredge(java.util.List)
*/
@Override
public Card chooseCardToDredge(List<Card> dredgers) {
if (GuiDialog.confirm(null, "Do you want to dredge?", false)) {
return GuiChoose.oneOrNone("Select card to dredge", dredgers);
}
return null;
}
}

View File

@@ -23,10 +23,7 @@ package forge.game.player;
* @author jendave
*/
public enum PlayerType {
/** The HUMAN. */
HUMAN,
/** The COMPUTER. */
COMPUTER
COMPUTER,
REMOTE
}

View File

@@ -153,22 +153,6 @@ public final class PlayerUtil {
return target;
} // input_discard()
/**
* <p>
* input_sacrificePermanent.
* </p>
*
* @param choices
* a {@link forge.CardList} object.
* @param message
* a {@link java.lang.String} object.
* @return a {@link forge.control.input.Input} object.
* @since 1.0.15
*/
public static Input inputSacrificePermanent(final List<Card> choices, final String message) {
return PlayerUtil.inputSacrificePermanentsFromList(1, choices, message);
} // input_sacrifice()
/**
* <p>
* input_sacrificePermanents.

View File

@@ -29,6 +29,7 @@ import forge.CardPredicates;
import forge.CardPredicates.Presets;
import forge.Command;
import forge.Singletons;
import forge.card.ability.AbilityFactory;
import forge.card.mana.ManaCost;
import forge.card.spellability.Ability;
import forge.card.spellability.SpellAbility;
@@ -142,30 +143,17 @@ public class PlayerZoneBattlefield extends PlayerZone {
}
final List<Card> les = c.getOwner().getOpponent().getCardsIn(ZoneType.Battlefield, "Land Equilibrium");
final Card lesLand = c;
if (les.size() > 0) {
final Card source = les.get(0);
final SpellAbility ability = new Ability(source, ManaCost.NO_COST) {
@Override
public void resolve() {
final List<Card> lands = lesLand.getOwner().getLandsInPlay();
lesLand.getOwner().sacrificePermanent(source.getName() + " - Select a land to sacrifice",
lands);
for( Player opp : c.getOwner().getOpponents())
for( Card le : opp.getCardsIn(ZoneType.Battlefield, "Land Equilibrium") ) {
final List<Card> pLands = c.getOwner().getLandsInPlay();
final List<Card> oLands = opp.getLandsInPlay();
if (oLands.size() <= (pLands.size() - 1)) {
SpellAbility abSac = AbilityFactory.getAbility(le.getSVar("SacLand"), le);
Singletons.getModel().getGame().getStack().addSimultaneousStackEntry(abSac);
}
};
final StringBuilder sb = new StringBuilder();
sb.append(source).append(" - ");
sb.append(tisLand.getController()).append(" sacrifices a land.");
ability.setStackDescription(sb.toString());
final List<Card> pLands = lesLand.getOwner().getLandsInPlay();
final List<Card> oLands = lesLand.getOwner().getOpponent().getLandsInPlay();
// (pLands - 1) because this land is in play, and the
// ability is before it is in play
if (oLands.size() <= (pLands.size() - 1)) {
Singletons.getModel().getGame().getStack().addSimultaneousStackEntry(ability);
}
}
} // isLand()
}

View File

@@ -28,7 +28,6 @@ import forge.deck.Deck;
import forge.game.GameFormat;
import forge.game.event.Event;
import forge.game.event.MulliganEvent;
import forge.game.player.PlayerType;
import forge.item.CardPrinted;
import forge.item.PreconDeck;
import forge.properties.NewConstants;
@@ -445,7 +444,8 @@ public class QuestController {
if ( ev instanceof MulliganEvent ) {
MulliganEvent mev = (MulliganEvent)ev;
// First mulligan is free
if (mev.player.getType() == PlayerType.HUMAN && getAssets().hasItem(QuestItemType.SLEIGHT) && mev.player.getStats().getMulliganCount() == 0) {
if (mev.player.getLobbyPlayer() == Singletons.getControl().getLobby().getQuestPlayer()
&& getAssets().hasItem(QuestItemType.SLEIGHT) && mev.player.getStats().getMulliganCount() == 0) {
mev.player.drawCard();
}
}

View File

@@ -0,0 +1,136 @@
package forge.quest;
import java.util.ArrayList;
import java.util.List;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import forge.Singletons;
import forge.card.CardRules;
import forge.item.CardPrinted;
import forge.item.IPaperCard;
import forge.item.InventoryItem;
/**
* TODO: Write javadoc for this type.
*
*/
public abstract class QuestRewardCard implements InventoryItem, IQuestRewardCard {
protected String buildDescription(final String [] input) {
final String defaultDescription = "a card";
if (input == null || input.length < 1) {
return defaultDescription;
}
String buildDesc = null;
for (String s : input) {
if (s.startsWith("desc:") || s.startsWith("Desc:")) {
String[] tmp = s.split(":");
if (tmp.length > 1) {
buildDesc = new String(tmp[1]);
} else {
buildDesc = new String();
}
} else if (buildDesc != null) {
if (s.contains(":")) {
return buildDesc;
} else {
buildDesc = buildDesc + " " + s;
}
}
}
if (buildDesc != null) {
return buildDesc;
}
return defaultDescription;
}
protected Predicate<CardPrinted> buildPredicates(final String [] input) {
if (input == null || input.length < 1) {
return null;
}
Predicate<CardPrinted> filters = Singletons.getModel().getQuest().getFormat().getFilterPrinted();
Predicate<CardRules> filterRules = null;
Predicate<CardPrinted> filterRarity = null;
for (String s : input) {
if (s.startsWith("sets:") || s.startsWith("Sets:")) {
final String[] tmp = s.split(":");
if (tmp.length > 1) {
String [] setcodes = tmp[1].split(",");
if (setcodes.length > 0) {
List<String> sets = new ArrayList<String>();
for (String code : setcodes) {
if (Singletons.getModel().getEditions().contains(code)) {
// System.out.println("Set " + code + " was found!");
sets.add(code);
}
// else { System.out.println("Unknown set code " + code); }
}
if (sets.size() > 0) {
filters = IPaperCard.Predicates.printedInSets(sets, true);
}
}
}
} else if (s.startsWith("rules:") || s.startsWith("Rules:")) {
final String[] tmp = s.split(":");
if (tmp.length > 1) {
String [] ruleCodes = tmp[1].split(",");
if (ruleCodes.length > 0) {
for (String rule : ruleCodes) {
final Predicate<CardRules> newRule = BoosterUtils.parseRulesLimitation(rule);
if (newRule != null) {
filterRules = (filterRules == null ? newRule : Predicates.and(filterRules, newRule));
}
}
}
}
} else if (s.startsWith("rarity:") || s.startsWith("Rarity:")) {
final String[] tmp = s.split(":");
if (tmp.length > 1) {
String [] rarityCodes = tmp[1].split(",");
if (rarityCodes.length > 0) {
for (String rarity : rarityCodes) {
if (rarity.startsWith("C") || rarity.startsWith("c")) {
filterRarity = (filterRarity == null ? IPaperCard.Predicates.Presets.IS_COMMON : Predicates.or(filterRarity, IPaperCard.Predicates.Presets.IS_COMMON));
} else if (rarity.startsWith("U") || rarity.startsWith("u")) {
filterRarity = (filterRarity == null ? IPaperCard.Predicates.Presets.IS_UNCOMMON : Predicates.or(filterRarity, IPaperCard.Predicates.Presets.IS_UNCOMMON));
} else if (rarity.startsWith("R") || rarity.startsWith("r")) {
filterRarity = (filterRarity == null ? IPaperCard.Predicates.Presets.IS_RARE : Predicates.or(filterRarity, IPaperCard.Predicates.Presets.IS_RARE));
} else if (rarity.startsWith("M") || rarity.startsWith("m")) {
filterRarity = (filterRarity == null ? IPaperCard.Predicates.Presets.IS_MYTHIC_RARE : Predicates.or(filterRarity, IPaperCard.Predicates.Presets.IS_MYTHIC_RARE));
}
}
}
}
}
}
if (filterRules != null) {
final Predicate<CardPrinted> rulesPrinted = Predicates.compose(filterRules, CardPrinted.FN_GET_RULES);
filters = Predicates.and(filters, rulesPrinted);
}
if (filterRarity != null) {
filters = Predicates.and(filters, filterRarity);
}
return filters;
}
/**
* A QuestRewardCardChooser ought to always be resolved to an actual card, hence no images.
*
* @return an empty string
*/
@Override
public String getImageKey() {
return "";
}
public abstract List<CardPrinted> getChoices();
}

View File

@@ -6,14 +6,11 @@ import java.util.List;
import java.util.Map;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import forge.Singletons;
import forge.card.CardRules;
import forge.item.CardDb;
import forge.item.CardPrinted;
import forge.item.IPaperCard;
import forge.item.InventoryItem;
import forge.item.ItemPool;
@@ -22,7 +19,7 @@ import forge.item.ItemPool;
* The initial version includes "duplicate", other type may be added later.
*
*/
public class QuestRewardCardChooser implements InventoryItem {
public class QuestRewardCardChooser extends QuestRewardCard implements InventoryItem {
/**
* Possible types for this object.
@@ -55,110 +52,6 @@ public class QuestRewardCardChooser implements InventoryItem {
}
}
private String buildDescription(final String [] input) {
final String defaultDescription = "a card";
if (input == null || input.length < 1) {
return defaultDescription;
}
String buildDesc = null;
for (String s : input) {
if (s.startsWith("desc:") || s.startsWith("Desc:")) {
String[] tmp = s.split(":");
if (tmp.length > 1) {
buildDesc = new String(tmp[1]);
} else {
buildDesc = new String();
}
} else if (buildDesc != null) {
if (s.contains(":")) {
return buildDesc;
} else {
buildDesc = buildDesc + " " + s;
}
}
}
if (buildDesc != null) {
return buildDesc;
}
return defaultDescription;
}
private Predicate<CardPrinted> buildPredicates(final String [] input) {
if (input == null || input.length < 1) {
return null;
}
Predicate<CardPrinted> filters = Singletons.getModel().getQuest().getFormat().getFilterPrinted();
Predicate<CardRules> filterRules = null;
Predicate<CardPrinted> filterRarity = null;
for (String s : input) {
if (s.startsWith("sets:") || s.startsWith("Sets:")) {
final String[] tmp = s.split(":");
if (tmp.length > 1) {
String [] setcodes = tmp[1].split(",");
if (setcodes.length > 0) {
List<String> sets = new ArrayList<String>();
for (String code : setcodes) {
if (Singletons.getModel().getEditions().contains(code)) {
// System.out.println("Set " + code + " was found!");
sets.add(code);
}
// else { System.out.println("Unknown set code " + code); }
}
if (sets.size() > 0) {
filters = IPaperCard.Predicates.printedInSets(sets, true);
}
}
}
} else if (s.startsWith("rules:") || s.startsWith("Rules:")) {
final String[] tmp = s.split(":");
if (tmp.length > 1) {
String [] ruleCodes = tmp[1].split(",");
if (ruleCodes.length > 0) {
for (String rule : ruleCodes) {
final Predicate<CardRules> newRule = BoosterUtils.parseRulesLimitation(rule);
if (newRule != null) {
filterRules = (filterRules == null ? newRule : Predicates.and(filterRules, newRule));
}
}
}
}
} else if (s.startsWith("rarity:") || s.startsWith("Rarity:")) {
final String[] tmp = s.split(":");
if (tmp.length > 1) {
String [] rarityCodes = tmp[1].split(",");
if (rarityCodes.length > 0) {
for (String rarity : rarityCodes) {
if (rarity.startsWith("C") || rarity.startsWith("c")) {
filterRarity = (filterRarity == null ? IPaperCard.Predicates.Presets.IS_COMMON : Predicates.or(filterRarity, IPaperCard.Predicates.Presets.IS_COMMON));
} else if (rarity.startsWith("U") || rarity.startsWith("u")) {
filterRarity = (filterRarity == null ? IPaperCard.Predicates.Presets.IS_UNCOMMON : Predicates.or(filterRarity, IPaperCard.Predicates.Presets.IS_UNCOMMON));
} else if (rarity.startsWith("R") || rarity.startsWith("r")) {
filterRarity = (filterRarity == null ? IPaperCard.Predicates.Presets.IS_RARE : Predicates.or(filterRarity, IPaperCard.Predicates.Presets.IS_RARE));
} else if (rarity.startsWith("M") || rarity.startsWith("m")) {
filterRarity = (filterRarity == null ? IPaperCard.Predicates.Presets.IS_MYTHIC_RARE : Predicates.or(filterRarity, IPaperCard.Predicates.Presets.IS_MYTHIC_RARE));
}
}
}
}
}
}
if (filterRules != null) {
final Predicate<CardPrinted> rulesPrinted = Predicates.compose(filterRules, CardPrinted.FN_GET_RULES);
filters = Predicates.and(filters, rulesPrinted);
}
if (filterRarity != null) {
filters = Predicates.and(filters, filterRarity);
}
return filters;
}
/**
* The name.
*
@@ -169,16 +62,6 @@ public class QuestRewardCardChooser implements InventoryItem {
return description;
}
/**
* A QuestRewardCardChooser ought to always be resolved to an actual card, hence no images.
*
* @return an empty string
*/
@Override
public String getImageKey() {
return "";
}
/**
* The item type.
*
@@ -207,6 +90,7 @@ public class QuestRewardCardChooser implements InventoryItem {
*
* @return a List<CardPrinted> or null if could not create a list.
*/
@Override
public final List<CardPrinted> getChoices() {
if (type == poolType.playerCards) {
final ItemPool<CardPrinted> playerCards = Singletons.getModel().getQuest().getAssets().getCardPool();

View File

@@ -5,20 +5,16 @@ import java.util.Collections;
import java.util.List;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import forge.Singletons;
import forge.card.CardRules;
import forge.item.CardDb;
import forge.item.CardPrinted;
import forge.item.IPaperCard;
/**
* Allows the player to choose a card from a predicate-filtered list of cards.
*
*/
public class QuestRewardCardFiltered implements IQuestRewardCard {
public class QuestRewardCardFiltered extends QuestRewardCard implements IQuestRewardCard {
private final String description;
private final Predicate<CardPrinted> predicates;
@@ -33,109 +29,7 @@ public class QuestRewardCardFiltered implements IQuestRewardCard {
}
private String buildDescription(final String [] input) {
final String defaultDescription = "a card";
if (input == null || input.length < 1) {
return defaultDescription;
}
String buildDesc = null;
for (String s : input) {
if (s.startsWith("desc:") || s.startsWith("Desc:")) {
String[] tmp = s.split(":");
if (tmp.length > 1) {
buildDesc = new String(tmp[1]);
} else {
buildDesc = new String();
}
} else if (buildDesc != null) {
if (s.contains(":")) {
return buildDesc;
} else {
buildDesc = buildDesc + " " + s;
}
}
}
if (buildDesc != null) {
return buildDesc;
}
return defaultDescription;
}
private Predicate<CardPrinted> buildPredicates(final String [] input) {
if (input == null || input.length < 1) {
return null;
}
Predicate<CardPrinted> filters = Singletons.getModel().getQuest().getFormat().getFilterPrinted();
Predicate<CardRules> filterRules = null;
Predicate<CardPrinted> filterRarity = null;
for (String s : input) {
if (s.startsWith("sets:") || s.startsWith("Sets:")) {
final String[] tmp = s.split(":");
if (tmp.length > 1) {
String [] setcodes = tmp[1].split(",");
if (setcodes.length > 0) {
List<String> sets = new ArrayList<String>();
for (String code : setcodes) {
if (Singletons.getModel().getEditions().contains(code)) {
// System.out.println("Set " + code + " was found!");
sets.add(code);
}
// else { System.out.println("Unknown set code " + code); }
}
if (sets.size() > 0) {
filters = IPaperCard.Predicates.printedInSets(sets, true);
}
}
}
} else if (s.startsWith("rules:") || s.startsWith("Rules:")) {
final String[] tmp = s.split(":");
if (tmp.length > 1) {
String [] ruleCodes = tmp[1].split(",");
if (ruleCodes.length > 0) {
for (String rule : ruleCodes) {
final Predicate<CardRules> newRule = BoosterUtils.parseRulesLimitation(rule);
if (newRule != null) {
filterRules = (filterRules == null ? newRule : Predicates.and(filterRules, newRule));
}
}
}
}
} else if (s.startsWith("rarity:") || s.startsWith("Rarity:")) {
final String[] tmp = s.split(":");
if (tmp.length > 1) {
String [] rarityCodes = tmp[1].split(",");
if (rarityCodes.length > 0) {
for (String rarity : rarityCodes) {
if (rarity.startsWith("C") || rarity.startsWith("c")) {
filterRarity = (filterRarity == null ? IPaperCard.Predicates.Presets.IS_COMMON : Predicates.or(filterRarity, IPaperCard.Predicates.Presets.IS_COMMON));
} else if (rarity.startsWith("U") || rarity.startsWith("u")) {
filterRarity = (filterRarity == null ? IPaperCard.Predicates.Presets.IS_UNCOMMON : Predicates.or(filterRarity, IPaperCard.Predicates.Presets.IS_UNCOMMON));
} else if (rarity.startsWith("R") || rarity.startsWith("r")) {
filterRarity = (filterRarity == null ? IPaperCard.Predicates.Presets.IS_RARE : Predicates.or(filterRarity, IPaperCard.Predicates.Presets.IS_RARE));
} else if (rarity.startsWith("M") || rarity.startsWith("m")) {
filterRarity = (filterRarity == null ? IPaperCard.Predicates.Presets.IS_MYTHIC_RARE : Predicates.or(filterRarity, IPaperCard.Predicates.Presets.IS_MYTHIC_RARE));
}
}
}
}
}
}
if (filterRules != null) {
final Predicate<CardPrinted> rulesPrinted = Predicates.compose(filterRules, CardPrinted.FN_GET_RULES);
filters = Predicates.and(filters, rulesPrinted);
}
if (filterRarity != null) {
filters = Predicates.and(filters, filterRarity);
}
return filters;
}
/**
/**
* The name.
*
* @return the name
@@ -145,15 +39,6 @@ public class QuestRewardCardFiltered implements IQuestRewardCard {
return description;
}
/**
* This class is a dynamic list of cards, hence no images.
*
* @return an empty string
*/
@Override
public String getImageKey() {
return "";
}
/**
* The item type.
@@ -170,6 +55,7 @@ public class QuestRewardCardFiltered implements IQuestRewardCard {
*
* @return a List<CardPrinted> or null if could not create a list.
*/
@Override
public final List<CardPrinted> getChoices() {
List<CardPrinted> cardChoices = new ArrayList<CardPrinted>();
for (final CardPrinted card : Iterables.filter(CardDb.instance().getAllCards(), predicates)) {