mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 12:18:00 +00:00
merge latest trunk
This commit is contained in:
@@ -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>.
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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")) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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")) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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")) {
|
||||
|
||||
@@ -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")) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,10 +23,7 @@ package forge.game.player;
|
||||
* @author jendave
|
||||
*/
|
||||
public enum PlayerType {
|
||||
|
||||
/** The HUMAN. */
|
||||
HUMAN,
|
||||
|
||||
/** The COMPUTER. */
|
||||
COMPUTER
|
||||
COMPUTER,
|
||||
REMOTE
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
136
src/main/java/forge/quest/QuestRewardCard.java
Normal file
136
src/main/java/forge/quest/QuestRewardCard.java
Normal 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();
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
Reference in New Issue
Block a user