mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 11:18:01 +00:00
Targeting code fixed to support fireballs and other spell with multiple targets.
Some classes had references to ArrayList instead of list, this was also changed
This commit is contained in:
2
.gitattributes
vendored
2
.gitattributes
vendored
@@ -13766,7 +13766,7 @@ src/main/java/forge/card/spellability/SpellAbilityVariables.java svneol=native#t
|
||||
src/main/java/forge/card/spellability/SpellPermanent.java svneol=native#text/plain
|
||||
src/main/java/forge/card/spellability/Target.java svneol=native#text/plain
|
||||
src/main/java/forge/card/spellability/TargetChoices.java svneol=native#text/plain
|
||||
src/main/java/forge/card/spellability/TargetSelection.java svneol=native#text/plain
|
||||
src/main/java/forge/card/spellability/TargetChooser.java svneol=native#text/plain
|
||||
src/main/java/forge/card/spellability/package-info.java svneol=native#text/plain
|
||||
src/main/java/forge/card/staticability/StaticAbility.java svneol=native#text/plain
|
||||
src/main/java/forge/card/staticability/StaticAbilityCantAttackBlock.java -text
|
||||
|
||||
@@ -623,7 +623,7 @@ public class AbilityUtils {
|
||||
|
||||
} else if (type.startsWith("Targeted")) {
|
||||
source = null;
|
||||
ArrayList<Card> tgts = sa.findTargetedCards();
|
||||
List<Card> tgts = sa.findTargetedCards();
|
||||
if (!tgts.isEmpty()) {
|
||||
source = tgts.get(0);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import forge.card.cardfactory.CardFactoryUtil;
|
||||
import forge.card.cost.Cost;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
import forge.card.spellability.Target;
|
||||
import forge.card.spellability.TargetSelection;
|
||||
import forge.card.spellability.TargetChooser;
|
||||
import forge.game.ai.ComputerUtilCard;
|
||||
import forge.game.ai.ComputerUtilCost;
|
||||
import forge.game.ai.ComputerUtilMana;
|
||||
@@ -50,7 +50,7 @@ public class CounterAi extends SpellAbilityAi {
|
||||
}
|
||||
|
||||
tgt.resetTargets();
|
||||
if (TargetSelection.matchSpellAbility(sa, topSA, tgt)) {
|
||||
if (TargetChooser.matchSpellAbility(sa, topSA, tgt)) {
|
||||
tgt.addTarget(topSA);
|
||||
} else {
|
||||
return false;
|
||||
@@ -120,7 +120,7 @@ public class CounterAi extends SpellAbilityAi {
|
||||
}
|
||||
|
||||
tgt.resetTargets();
|
||||
if (TargetSelection.matchSpellAbility(sa, topSA, tgt)) {
|
||||
if (TargetChooser.matchSpellAbility(sa, topSA, tgt)) {
|
||||
tgt.addTarget(topSA);
|
||||
} else {
|
||||
return false;
|
||||
|
||||
@@ -15,7 +15,7 @@ import forge.card.cost.Cost;
|
||||
import forge.card.spellability.AbilitySub;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
import forge.card.spellability.Target;
|
||||
import forge.card.spellability.TargetSelection;
|
||||
import forge.card.spellability.TargetChooser;
|
||||
import forge.game.ai.ComputerUtil;
|
||||
import forge.game.ai.ComputerUtilCard;
|
||||
import forge.game.ai.ComputerUtilCombat;
|
||||
@@ -103,8 +103,7 @@ public class DamageDealAi extends DamageAiBase {
|
||||
if (tgt != null && tgt.getTargetPlayers().isEmpty() && !sa.hasParam("DividedAsYouChoose")) {
|
||||
int actualPay = 0;
|
||||
final boolean noPrevention = sa.hasParam("NoPrevention");
|
||||
final ArrayList<Card> cards = tgt.getTargetCards();
|
||||
for (final Card c : cards) {
|
||||
for (final Card c : tgt.getTargetCards()) {
|
||||
final int adjDamage = ComputerUtilCombat.getEnoughDamageToKill(c, dmg, source, false, noPrevention);
|
||||
if ((adjDamage > actualPay) && (adjDamage <= dmg)) {
|
||||
actualPay = adjDamage;
|
||||
@@ -144,7 +143,7 @@ public class DamageDealAi extends DamageAiBase {
|
||||
|
||||
final ArrayList<Object> objects = tgt.getTargets();
|
||||
if (saMe.hasParam("TargetUnique")) {
|
||||
objects.addAll(TargetSelection.getUniqueTargets(saMe));
|
||||
objects.addAll(TargetChooser.getUniqueTargets(saMe));
|
||||
}
|
||||
for (final Object o : objects) {
|
||||
if (o instanceof Card) {
|
||||
@@ -472,7 +471,7 @@ public class DamageDealAi extends DamageAiBase {
|
||||
// If I can kill my target by paying less mana, do it
|
||||
int actualPay = 0;
|
||||
final boolean noPrevention = sa.hasParam("NoPrevention");
|
||||
final ArrayList<Card> cards = tgt.getTargetCards();
|
||||
final List<Card> cards = tgt.getTargetCards();
|
||||
//target is a player
|
||||
if (cards.isEmpty()) {
|
||||
actualPay = dmg;
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
*/
|
||||
package forge.card.ability.ai;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import forge.Card;
|
||||
@@ -96,7 +96,7 @@ public class DrawAi extends SpellAbilityAi {
|
||||
}
|
||||
|
||||
if (tgt != null) {
|
||||
final ArrayList<Player> players = tgt.getTargetPlayers();
|
||||
final List<Player> players = tgt.getTargetPlayers();
|
||||
if ((players.size() > 0) && players.get(0).isOpponentOf(ai)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
|
||||
final StringBuilder sbTargets = new StringBuilder();
|
||||
|
||||
ArrayList<Card> tgts;
|
||||
List<Card> tgts;
|
||||
if (sa.getTarget() != null) {
|
||||
tgts = sa.getTarget().getTargetCards();
|
||||
} else {
|
||||
@@ -301,8 +301,8 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
* a {@link forge.card.spellability.SpellAbility} object.
|
||||
*/
|
||||
private static void changeKnownOriginResolve(final SpellAbility sa) {
|
||||
ArrayList<Card> tgtCards;
|
||||
ArrayList<SpellAbility> sas;
|
||||
List<Card> tgtCards;
|
||||
List<SpellAbility> sas;
|
||||
|
||||
final Target tgt = sa.getTarget();
|
||||
final Player player = sa.getActivatingPlayer();
|
||||
@@ -552,7 +552,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
|
||||
final Target tgt = sa.getTarget();
|
||||
if (tgt != null) {
|
||||
final ArrayList<Player> players = tgt.getTargetPlayers();
|
||||
final List<Player> players = tgt.getTargetPlayers();
|
||||
player = player != null ? player : players.get(0);
|
||||
if (players.contains(player) && !player.canBeTargetedBy(sa)) {
|
||||
return;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package forge.card.ability.effects;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import forge.Card;
|
||||
import forge.Singletons;
|
||||
@@ -21,7 +21,7 @@ public class ControlExchangeEffect extends SpellAbilityEffect {
|
||||
Card object1 = null;
|
||||
Card object2 = null;
|
||||
final Target tgt = sa.getTarget();
|
||||
ArrayList<Card> tgts = tgt.getTargetCards();
|
||||
List<Card> tgts = tgt.getTargetCards();
|
||||
if (tgts.size() > 0) {
|
||||
object1 = tgts.get(0);
|
||||
}
|
||||
@@ -42,7 +42,7 @@ public class ControlExchangeEffect extends SpellAbilityEffect {
|
||||
Card object1 = null;
|
||||
Card object2 = null;
|
||||
final Target tgt = sa.getTarget();
|
||||
ArrayList<Card> tgts = tgt.getTargetCards();
|
||||
List<Card> tgts = tgt.getTargetCards();
|
||||
if (tgts.size() > 0) {
|
||||
object1 = tgts.get(0);
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ public class DestroyAllEffect extends SpellAbilityEffect {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
final boolean noRegen = sa.hasParam("NoRegen");
|
||||
|
||||
ArrayList<Card> tgtCards;
|
||||
List<Card> tgtCards;
|
||||
|
||||
final Target tgt = sa.getTarget();
|
||||
if (tgt != null) {
|
||||
|
||||
@@ -34,7 +34,6 @@ import forge.CardPredicates.Presets;
|
||||
import forge.Command;
|
||||
import forge.CounterType;
|
||||
import forge.Singletons;
|
||||
import forge.card.ability.AbilityFactory;
|
||||
import forge.card.cost.Cost;
|
||||
import forge.card.mana.ManaCost;
|
||||
import forge.card.spellability.Ability;
|
||||
|
||||
@@ -2919,7 +2919,7 @@ public class CardFactoryUtil {
|
||||
}
|
||||
|
||||
if (card.getController().isHuman()) {
|
||||
game.getActionPlay().playSpellAbilityNoStack(card.getController(), origSA, false);
|
||||
game.getActionPlay().playSpellAbilityNoStack(card.getController(), origSA);
|
||||
} else {
|
||||
ComputerUtil.playNoStack((AIPlayer) card.getController(), origSA, game);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ import com.google.common.base.Predicate;
|
||||
|
||||
import forge.Card;
|
||||
import forge.CardLists;
|
||||
import forge.CardPredicates;
|
||||
import forge.CardPredicates.Presets;
|
||||
import forge.FThreads;
|
||||
import forge.card.ability.AbilityUtils;
|
||||
|
||||
@@ -239,7 +239,7 @@ public class ReplacementHandler {
|
||||
Player player = replacementEffect.getHostCard().getController();
|
||||
//player.getController().playNoStack()
|
||||
if (player.isHuman()) {
|
||||
game.getActionPlay().playSpellAbilityNoStack(player, effectSA, false);
|
||||
game.getActionPlay().playSpellAbilityNoStack(player, effectSA);
|
||||
} else {
|
||||
ComputerUtil.playNoStack((AIPlayer) player, effectSA, game);
|
||||
}
|
||||
|
||||
@@ -1053,7 +1053,7 @@ public abstract class SpellAbility implements ISpellAbility {
|
||||
if (this.targetCard == null) {
|
||||
final Target tgt = this.getTarget();
|
||||
if (tgt != null) {
|
||||
final ArrayList<Card> list = tgt.getTargetCards();
|
||||
final List<Card> list = tgt.getTargetCards();
|
||||
|
||||
if (!list.isEmpty()) {
|
||||
return list.get(0);
|
||||
@@ -1106,7 +1106,7 @@ public abstract class SpellAbility implements ISpellAbility {
|
||||
public Player getTargetPlayer() {
|
||||
final Target tgt = this.getTarget();
|
||||
if (tgt != null) {
|
||||
final ArrayList<Player> list = tgt.getTargetPlayers();
|
||||
final List<Player> list = tgt.getTargetPlayers();
|
||||
|
||||
if (!list.isEmpty()) {
|
||||
return list.get(0);
|
||||
@@ -1313,7 +1313,7 @@ public abstract class SpellAbility implements ISpellAbility {
|
||||
return false;
|
||||
}
|
||||
if (entity.isValid(this.getTarget().getValidTgts(), this.getActivatingPlayer(), this.getSourceCard())
|
||||
&& (!this.getTarget().isUniqueTargets() || !TargetSelection.getUniqueTargets(this).contains(entity))
|
||||
&& (!this.getTarget().isUniqueTargets() || !TargetChooser.getUniqueTargets(this).contains(entity))
|
||||
&& entity.canBeTargetedBy(this)) {
|
||||
return true;
|
||||
}
|
||||
@@ -1494,23 +1494,22 @@ public abstract class SpellAbility implements ISpellAbility {
|
||||
*
|
||||
* @return a {@link forge.card.spellability.SpellAbility} object.
|
||||
*/
|
||||
public ArrayList<Card> findTargetedCards() {
|
||||
|
||||
ArrayList<Card> list = new ArrayList<Card>();
|
||||
public List<Card> findTargetedCards() {
|
||||
Target tgt = this.getTarget();
|
||||
// First search for targeted cards associated with current ability
|
||||
if (tgt != null && tgt.getTargetCards() != null && !tgt.getTargetCards().isEmpty()) {
|
||||
return tgt.getTargetCards();
|
||||
}
|
||||
List<Card> list = new ArrayList<Card>();
|
||||
// Next search for source cards of targeted SAs associated with current ability
|
||||
else if (tgt != null && tgt.getTargetSAs() != null && !tgt.getTargetSAs().isEmpty()) {
|
||||
if (tgt != null && tgt.getTargetSAs() != null && !tgt.getTargetSAs().isEmpty()) {
|
||||
for (final SpellAbility ability : tgt.getTargetSAs()) {
|
||||
list.add(ability.getSourceCard());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
// Lastly Search parent SAs for target cards
|
||||
else {
|
||||
|
||||
// Check for a parent that targets a card
|
||||
SpellAbility parent = this.getParentTargetingCard();
|
||||
if (null != parent) {
|
||||
@@ -1523,7 +1522,7 @@ public abstract class SpellAbility implements ISpellAbility {
|
||||
list.add(ability.getSourceCard());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
@@ -38,48 +38,36 @@ import forge.game.zone.Zone;
|
||||
* @version $Id$
|
||||
*/
|
||||
public class SpellAbilityRequirements {
|
||||
private SpellAbility ability = null;
|
||||
private TargetSelection select = null;
|
||||
private CostPayment payment = null;
|
||||
private boolean isFree = false;
|
||||
private final SpellAbility ability;
|
||||
private final TargetChooser select;
|
||||
private final CostPayment payment;
|
||||
private boolean isFree;
|
||||
private boolean skipStack = false;
|
||||
private boolean bCasting = false;
|
||||
private Zone fromZone = null;
|
||||
private Integer zonePosition = null;
|
||||
private boolean isAlreadyTargeted = false;
|
||||
|
||||
|
||||
public final void setSkipStack(final boolean bSkip) {
|
||||
this.skipStack = bSkip;
|
||||
}
|
||||
|
||||
public final void setFree(final boolean bFree) {
|
||||
this.isFree = bFree;
|
||||
}
|
||||
public void setAlreadyTargeted() { isAlreadyTargeted = true; }
|
||||
public final void setSkipStack() { this.skipStack = true; }
|
||||
public void setFree() { this.isFree = true; }
|
||||
|
||||
|
||||
public SpellAbilityRequirements(final SpellAbility sa, final TargetSelection ts, final CostPayment cp) {
|
||||
public SpellAbilityRequirements(final SpellAbility sa, final CostPayment cp) {
|
||||
this.ability = sa;
|
||||
this.select = ts;
|
||||
this.select = new TargetChooser(sa);
|
||||
this.payment = cp;
|
||||
}
|
||||
|
||||
|
||||
public final void fillRequirements() {
|
||||
this.fillRequirements(false);
|
||||
}
|
||||
|
||||
public final void fillRequirements(final boolean skipTargeting) {
|
||||
final GameState game = Singletons.getModel().getGame();
|
||||
|
||||
if ((this.ability instanceof Spell) && !this.bCasting) {
|
||||
// remove from hand
|
||||
this.bCasting = true;
|
||||
if (!this.ability.getSourceCard().isCopiedSpell()) {
|
||||
final Card c = this.ability.getSourceCard();
|
||||
|
||||
this.fromZone = game.getZoneOf(c);
|
||||
this.zonePosition = this.fromZone.getPosition(c);
|
||||
this.ability.setSourceCard(game.getAction().moveToStack(c));
|
||||
}
|
||||
// used to rollback
|
||||
Zone fromZone = null;
|
||||
int zonePosition = 0;
|
||||
|
||||
final Card c = this.ability.getSourceCard();
|
||||
if (this.ability instanceof Spell && !c.isCopiedSpell()) {
|
||||
fromZone = game.getZoneOf(c);
|
||||
zonePosition = fromZone.getPosition(c);
|
||||
this.ability.setSourceCard(game.getAction().moveToStack(c));
|
||||
}
|
||||
|
||||
// freeze Stack. No abilities should go onto the stack while I'm filling requirements.
|
||||
@@ -88,19 +76,19 @@ public class SpellAbilityRequirements {
|
||||
// Announce things like how many times you want to Multikick or the value of X
|
||||
if (!this.announceRequirements()) {
|
||||
this.select.setCancel(true);
|
||||
rollbackAbility();
|
||||
rollbackAbility(fromZone, zonePosition);
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip to paying if parent ability doesn't target and has no
|
||||
// subAbilities.
|
||||
// (or trigger case where its already targeted)
|
||||
if (!skipTargeting && (this.select.doesTarget() || (this.ability.getSubAbility() != null))) {
|
||||
this.select.setRequirements(this);
|
||||
boolean acceptsTargets = this.select.doesTarget() || this.ability.getSubAbility() != null;
|
||||
if (!isAlreadyTargeted && acceptsTargets) {
|
||||
this.select.clearTargets();
|
||||
this.select.chooseTargets();
|
||||
if (this.select.isCanceled()) {
|
||||
rollbackAbility();
|
||||
rollbackAbility(fromZone, zonePosition);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -114,7 +102,7 @@ public class SpellAbilityRequirements {
|
||||
}
|
||||
|
||||
if (!paymentMade) {
|
||||
rollbackAbility();
|
||||
rollbackAbility(fromZone, zonePosition);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -134,7 +122,7 @@ public class SpellAbilityRequirements {
|
||||
}
|
||||
}
|
||||
|
||||
private void rollbackAbility() {
|
||||
private void rollbackAbility(Zone fromZone, int zonePosition) {
|
||||
// cancel ability during target choosing
|
||||
final Card c = this.ability.getSourceCard();
|
||||
|
||||
@@ -143,9 +131,9 @@ public class SpellAbilityRequirements {
|
||||
c.setState(CardCharacteristicName.Original);
|
||||
}
|
||||
|
||||
if (this.bCasting && !c.isCopiedSpell()) { // and not a copy
|
||||
if (fromZone != null) { // and not a copy
|
||||
// add back to where it came from
|
||||
Singletons.getModel().getGame().getAction().moveTo(this.fromZone, c, this.zonePosition);
|
||||
Singletons.getModel().getGame().getAction().moveTo(fromZone, c, zonePosition >= 0 ? Integer.valueOf(zonePosition) : null);
|
||||
}
|
||||
|
||||
if (this.select != null) {
|
||||
|
||||
@@ -464,7 +464,7 @@ public class Target {
|
||||
*
|
||||
* @return a {@link java.util.ArrayList} object.
|
||||
*/
|
||||
public final ArrayList<Card> getTargetCards() {
|
||||
public final List<Card> getTargetCards() {
|
||||
if (this.choice == null) {
|
||||
return new ArrayList<Card>();
|
||||
}
|
||||
@@ -479,7 +479,7 @@ public class Target {
|
||||
*
|
||||
* @return a {@link java.util.ArrayList} object.
|
||||
*/
|
||||
public final ArrayList<Player> getTargetPlayers() {
|
||||
public final List<Player> getTargetPlayers() {
|
||||
if (this.choice == null) {
|
||||
return new ArrayList<Player>();
|
||||
}
|
||||
@@ -494,7 +494,7 @@ public class Target {
|
||||
*
|
||||
* @return a {@link java.util.ArrayList} object.
|
||||
*/
|
||||
public final ArrayList<SpellAbility> getTargetSAs() {
|
||||
public final List<SpellAbility> getTargetSAs() {
|
||||
if (this.choice == null) {
|
||||
return new ArrayList<SpellAbility>();
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
package forge.card.spellability;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import forge.Card;
|
||||
import forge.game.player.Player;
|
||||
@@ -45,9 +46,9 @@ public class TargetChoices {
|
||||
}
|
||||
|
||||
// Card or Player are legal targets.
|
||||
private final ArrayList<Card> targetCards = new ArrayList<Card>();
|
||||
private final ArrayList<Player> targetPlayers = new ArrayList<Player>();
|
||||
private final ArrayList<SpellAbility> targetSAs = new ArrayList<SpellAbility>();
|
||||
private final List<Card> targetCards = new ArrayList<Card>();
|
||||
private final List<Player> targetPlayers = new ArrayList<Player>();
|
||||
private final List<SpellAbility> targetSAs = new ArrayList<SpellAbility>();
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -199,7 +200,7 @@ public class TargetChoices {
|
||||
*
|
||||
* @return a {@link java.util.ArrayList} object.
|
||||
*/
|
||||
public final ArrayList<Card> getTargetCards() {
|
||||
public final List<Card> getTargetCards() {
|
||||
return this.targetCards;
|
||||
}
|
||||
|
||||
@@ -210,7 +211,7 @@ public class TargetChoices {
|
||||
*
|
||||
* @return a {@link java.util.ArrayList} object.
|
||||
*/
|
||||
public final ArrayList<Player> getTargetPlayers() {
|
||||
public final List<Player> getTargetPlayers() {
|
||||
return this.targetPlayers;
|
||||
}
|
||||
|
||||
@@ -221,7 +222,7 @@ public class TargetChoices {
|
||||
*
|
||||
* @return a {@link java.util.ArrayList} object.
|
||||
*/
|
||||
public final ArrayList<SpellAbility> getTargetSAs() {
|
||||
public final List<SpellAbility> getTargetSAs() {
|
||||
return this.targetSAs;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,20 +20,23 @@ package forge.card.spellability;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
|
||||
import forge.Card;
|
||||
import forge.CardLists;
|
||||
import forge.FThreads;
|
||||
import forge.Singletons;
|
||||
import forge.GameEntity;
|
||||
import forge.card.ability.AbilityUtils;
|
||||
import forge.card.ability.ApiType;
|
||||
import forge.control.input.InputSynchronized;
|
||||
import forge.control.input.InputSyncronizedBase;
|
||||
import forge.game.GameState;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.zone.Zone;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.gui.GuiChoose;
|
||||
import forge.gui.match.CMatchUI;
|
||||
import forge.view.ButtonUtil;
|
||||
|
||||
/**
|
||||
@@ -44,21 +47,24 @@ import forge.view.ButtonUtil;
|
||||
* @author Forge
|
||||
* @version $Id$
|
||||
*/
|
||||
public class TargetSelection {
|
||||
public class TargetChooser {
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public final class InputSelectTargets extends InputSyncronizedBase {
|
||||
private final TargetSelection select;
|
||||
public static final class InputSelectTargets extends InputSyncronizedBase {
|
||||
private final List<Card> choices;
|
||||
private final ArrayList<Object> alreadyTargeted;
|
||||
private final boolean targeted;
|
||||
// some cards can be targeted several times (eg: distribute damage as you choose)
|
||||
private final Map<GameEntity, Integer> targetDepth = new HashMap<GameEntity, Integer>();
|
||||
private final Target tgt;
|
||||
private final SpellAbility sa;
|
||||
private boolean bCancel = false;
|
||||
private boolean bOk = false;
|
||||
private final boolean mandatory;
|
||||
private static final long serialVersionUID = -1091595663541356356L;
|
||||
|
||||
public final boolean hasCancelled() { return bCancel; }
|
||||
public final boolean hasPressedOk() { return bOk; }
|
||||
/**
|
||||
* TODO: Write javadoc for Constructor.
|
||||
* @param select
|
||||
@@ -70,13 +76,10 @@ public class TargetSelection {
|
||||
* @param sa
|
||||
* @param mandatory
|
||||
*/
|
||||
public InputSelectTargets(TargetSelection select, List<Card> choices, ArrayList<Object> alreadyTargeted, boolean targeted, Target tgt, SpellAbility sa, boolean mandatory) {
|
||||
public InputSelectTargets(List<Card> choices, SpellAbility sa, boolean mandatory) {
|
||||
super(sa.getActivatingPlayer());
|
||||
this.select = select;
|
||||
this.choices = choices;
|
||||
this.alreadyTargeted = alreadyTargeted;
|
||||
this.targeted = targeted;
|
||||
this.tgt = tgt;
|
||||
this.tgt = sa.getTarget();
|
||||
this.sa = sa;
|
||||
this.mandatory = mandatory;
|
||||
}
|
||||
@@ -84,12 +87,14 @@ public class TargetSelection {
|
||||
@Override
|
||||
public void showMessage() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append("Targeted: ");
|
||||
for (final Object o : alreadyTargeted) {
|
||||
sb.append(o).append(" ");
|
||||
sb.append("Targeted:\n");
|
||||
for (final Entry<GameEntity, Integer> o : targetDepth.entrySet()) {
|
||||
sb.append(o.getKey());
|
||||
if( o.getValue() > 1 )
|
||||
sb.append(" (").append(o.getValue()).append(" times)");
|
||||
sb.append("\n");
|
||||
}
|
||||
sb.append(tgt.getTargetedString());
|
||||
sb.append("\n");
|
||||
//sb.append(tgt.getTargetedString()).append("\n");
|
||||
sb.append(tgt.getVTSelection());
|
||||
|
||||
showMessage(sb.toString());
|
||||
@@ -114,110 +119,147 @@ public class TargetSelection {
|
||||
|
||||
@Override
|
||||
public void selectButtonCancel() {
|
||||
select.setCancel(true);
|
||||
bCancel = true;
|
||||
this.done();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectButtonOK() {
|
||||
bOk = true;
|
||||
this.done();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectCard(final Card card) {
|
||||
// leave this in temporarily, there some seriously wrong things
|
||||
// going on here
|
||||
if (targeted && !card.canBeTargetedBy(sa)) {
|
||||
CMatchUI.SINGLETON_INSTANCE.showMessage("Cannot target this card (Shroud? Protection? Restrictions?).");
|
||||
} else if (choices.contains(card)) {
|
||||
if (tgt.isDividedAsYouChoose()) {
|
||||
final int stillToDivide = tgt.getStillToDivide();
|
||||
int allocatedPortion = 0;
|
||||
// allow allocation only if the max targets isn't reached and there are more candidates
|
||||
if ((tgt.getNumTargeted() + 1 < tgt.getMaxTargets(sa.getSourceCard(), sa))
|
||||
&& (tgt.getNumCandidates(sa, true) - 1 > 0) && stillToDivide > 1) {
|
||||
final Integer[] choices = new Integer[stillToDivide];
|
||||
for (int i = 1; i <= stillToDivide; i++) {
|
||||
choices[i - 1] = i;
|
||||
}
|
||||
String apiBasedMessage = "Distribute how much to ";
|
||||
if (sa.getApi() == ApiType.DealDamage) {
|
||||
apiBasedMessage = "Select how much damage to deal to ";
|
||||
} else if (sa.getApi() == ApiType.PreventDamage) {
|
||||
apiBasedMessage = "Select how much damage to prevent to ";
|
||||
} else if (sa.getApi() == ApiType.PutCounter) {
|
||||
apiBasedMessage = "Select how many counters to distribute to ";
|
||||
}
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append(apiBasedMessage);
|
||||
sb.append(card.toString());
|
||||
Integer chosen = GuiChoose.oneOrNone(sb.toString(), choices);
|
||||
if (null == chosen) {
|
||||
return;
|
||||
}
|
||||
allocatedPortion = chosen;
|
||||
} else { // otherwise assign the rest of the damage/protection
|
||||
allocatedPortion = stillToDivide;
|
||||
}
|
||||
tgt.setStillToDivide(stillToDivide - allocatedPortion);
|
||||
tgt.addDividedAllocation(card, allocatedPortion);
|
||||
}
|
||||
tgt.addTarget(card);
|
||||
this.done();
|
||||
if (!tgt.isUniqueTargets() && targetDepth.containsKey(card)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// leave this in temporarily, there some seriously wrong things going on here
|
||||
if (!card.canBeTargetedBy(sa)) {
|
||||
showMessage("Cannot target this card (Shroud? Protection? Restrictions?).");
|
||||
return;
|
||||
}
|
||||
if (!choices.contains(card)) {
|
||||
showMessage("This card is not a valid choice for some other reason besides (Shroud? Protection? Restrictions?).");
|
||||
return;
|
||||
}
|
||||
|
||||
if (tgt.isDividedAsYouChoose()) {
|
||||
final int stillToDivide = tgt.getStillToDivide();
|
||||
int allocatedPortion = 0;
|
||||
// allow allocation only if the max targets isn't reached and there are more candidates
|
||||
if ((tgt.getNumTargeted() + 1 < tgt.getMaxTargets(sa.getSourceCard(), sa))
|
||||
&& (tgt.getNumCandidates(sa, true) - 1 > 0) && stillToDivide > 1) {
|
||||
final Integer[] choices = new Integer[stillToDivide];
|
||||
for (int i = 1; i <= stillToDivide; i++) {
|
||||
choices[i - 1] = i;
|
||||
}
|
||||
String apiBasedMessage = "Distribute how much to ";
|
||||
if (sa.getApi() == ApiType.DealDamage) {
|
||||
apiBasedMessage = "Select how much damage to deal to ";
|
||||
} else if (sa.getApi() == ApiType.PreventDamage) {
|
||||
apiBasedMessage = "Select how much damage to prevent to ";
|
||||
} else if (sa.getApi() == ApiType.PutCounter) {
|
||||
apiBasedMessage = "Select how many counters to distribute to ";
|
||||
}
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append(apiBasedMessage);
|
||||
sb.append(card.toString());
|
||||
Integer chosen = GuiChoose.oneOrNone(sb.toString(), choices);
|
||||
if (null == chosen) {
|
||||
return;
|
||||
}
|
||||
allocatedPortion = chosen;
|
||||
} else { // otherwise assign the rest of the damage/protection
|
||||
allocatedPortion = stillToDivide;
|
||||
}
|
||||
tgt.setStillToDivide(stillToDivide - allocatedPortion);
|
||||
tgt.addDividedAllocation(card, allocatedPortion);
|
||||
}
|
||||
addTarget(card);
|
||||
} // selectCard()
|
||||
|
||||
@Override
|
||||
public void selectPlayer(final Player player) {
|
||||
if (alreadyTargeted.contains(player)) {
|
||||
if (!tgt.isUniqueTargets() && targetDepth.containsKey(player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sa.canTarget(player)) {
|
||||
if (tgt.isDividedAsYouChoose()) {
|
||||
final int stillToDivide = tgt.getStillToDivide();
|
||||
int allocatedPortion = 0;
|
||||
// allow allocation only if the max targets isn't reached and there are more candidates
|
||||
if ((alreadyTargeted.size() + 1 < tgt.getMaxTargets(sa.getSourceCard(), sa))
|
||||
&& (tgt.getNumCandidates(sa, true) - 1 > 0) && stillToDivide > 1) {
|
||||
final Integer[] choices = new Integer[stillToDivide];
|
||||
for (int i = 1; i <= stillToDivide; i++) {
|
||||
choices[i - 1] = i;
|
||||
}
|
||||
String apiBasedMessage = "Distribute how much to ";
|
||||
if (sa.getApi() == ApiType.DealDamage) {
|
||||
apiBasedMessage = "Select how much damage to deal to ";
|
||||
} else if (sa.getApi() == ApiType.PreventDamage) {
|
||||
apiBasedMessage = "Select how much damage to prevent to ";
|
||||
}
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append(apiBasedMessage);
|
||||
sb.append(player.getName());
|
||||
Integer chosen = GuiChoose.oneOrNone(sb.toString(), choices);
|
||||
if (null == chosen) {
|
||||
return;
|
||||
}
|
||||
allocatedPortion = chosen;
|
||||
} else { // otherwise assign the rest of the damage/protection
|
||||
allocatedPortion = stillToDivide;
|
||||
}
|
||||
tgt.setStillToDivide(stillToDivide - allocatedPortion);
|
||||
tgt.addDividedAllocation(player, allocatedPortion);
|
||||
}
|
||||
tgt.addTarget(player);
|
||||
this.done();
|
||||
if (!sa.canTarget(player)) {
|
||||
showMessage("Cannot target this player (Hexproof? Protection? Restrictions?).");
|
||||
return;
|
||||
}
|
||||
|
||||
if (tgt.isDividedAsYouChoose()) {
|
||||
final int stillToDivide = tgt.getStillToDivide();
|
||||
int allocatedPortion = 0;
|
||||
// allow allocation only if the max targets isn't reached and there are more candidates
|
||||
if ((tgt.getNumTargeted() + 1 < tgt.getMaxTargets(sa.getSourceCard(), sa)) && (tgt.getNumCandidates(sa, true) - 1 > 0) && stillToDivide > 1) {
|
||||
final Integer[] choices = new Integer[stillToDivide];
|
||||
for (int i = 1; i <= stillToDivide; i++) {
|
||||
choices[i - 1] = i;
|
||||
}
|
||||
String apiBasedMessage = "Distribute how much to ";
|
||||
if (sa.getApi() == ApiType.DealDamage) {
|
||||
apiBasedMessage = "Select how much damage to deal to ";
|
||||
} else if (sa.getApi() == ApiType.PreventDamage) {
|
||||
apiBasedMessage = "Select how much damage to prevent to ";
|
||||
}
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append(apiBasedMessage);
|
||||
sb.append(player.getName());
|
||||
Integer chosen = GuiChoose.oneOrNone(sb.toString(), choices);
|
||||
if (null == chosen) {
|
||||
return;
|
||||
}
|
||||
allocatedPortion = chosen;
|
||||
} else { // otherwise assign the rest of the damage/protection
|
||||
allocatedPortion = stillToDivide;
|
||||
}
|
||||
tgt.setStillToDivide(stillToDivide - allocatedPortion);
|
||||
tgt.addDividedAllocation(player, allocatedPortion);
|
||||
}
|
||||
addTarget(player);
|
||||
}
|
||||
|
||||
void addTarget(GameEntity ge) {
|
||||
tgt.addTarget(ge);
|
||||
Integer val = targetDepth.get(ge);
|
||||
targetDepth.put(ge, val == null ? Integer.valueOf(1) : Integer.valueOf(val.intValue() + 1) );
|
||||
|
||||
if(hasAllTargets()) {
|
||||
bOk = true;
|
||||
this.done();
|
||||
}
|
||||
else
|
||||
this.showMessage();
|
||||
}
|
||||
|
||||
void done() {
|
||||
this.stop();
|
||||
}
|
||||
|
||||
boolean hasAllTargets() {
|
||||
return tgt.isMaxTargetsChosen(sa.getSourceCard(), sa);
|
||||
}
|
||||
}
|
||||
|
||||
private final Target target;
|
||||
private final SpellAbility ability;
|
||||
|
||||
private TargetSelection subSelection = null;
|
||||
/**
|
||||
* <p>
|
||||
* Constructor for Target_Selection.
|
||||
* </p>
|
||||
*
|
||||
* @param tgt
|
||||
* a {@link forge.card.spellability.Target} object.
|
||||
* @param sa
|
||||
* a {@link forge.card.spellability.SpellAbility} object.
|
||||
*/
|
||||
public TargetChooser(final SpellAbility sa) {
|
||||
this.ability = sa;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -227,7 +269,7 @@ public class TargetSelection {
|
||||
* @return a {@link forge.card.spellability.Target} object.
|
||||
*/
|
||||
public final Target getTgt() {
|
||||
return this.target;
|
||||
return this.ability.getTarget();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -252,20 +294,7 @@ public class TargetSelection {
|
||||
return this.ability.getSourceCard();
|
||||
}
|
||||
|
||||
private SpellAbilityRequirements req = null;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* setRequirements.
|
||||
* </p>
|
||||
*
|
||||
* @param reqs
|
||||
* a {@link forge.card.spellability.SpellAbilityRequirements}
|
||||
* object.
|
||||
*/
|
||||
public final void setRequirements(final SpellAbilityRequirements reqs) {
|
||||
this.req = reqs;
|
||||
}
|
||||
private TargetChooser subSelection = null;
|
||||
|
||||
private boolean bCancel = false;
|
||||
private boolean bTargetingDone = false;
|
||||
@@ -290,44 +319,12 @@ public class TargetSelection {
|
||||
* @return a boolean.
|
||||
*/
|
||||
public final boolean isCanceled() {
|
||||
if (this.bCancel) {
|
||||
return this.bCancel;
|
||||
}
|
||||
|
||||
if (this.subSelection == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.subSelection.isCanceled();
|
||||
return this.bCancel || this.subSelection != null && this.subSelection.isCanceled();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Constructor for Target_Selection.
|
||||
* </p>
|
||||
*
|
||||
* @param tgt
|
||||
* a {@link forge.card.spellability.Target} object.
|
||||
* @param sa
|
||||
* a {@link forge.card.spellability.SpellAbility} object.
|
||||
*/
|
||||
public TargetSelection(final Target tgt, final SpellAbility sa) {
|
||||
this.target = tgt;
|
||||
this.ability = sa;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* doesTarget.
|
||||
* </p>
|
||||
*
|
||||
* @return a boolean.
|
||||
*/
|
||||
public final boolean doesTarget() {
|
||||
if (this.target == null) {
|
||||
return false;
|
||||
}
|
||||
return this.target.doesTarget();
|
||||
Target tg = getTgt();
|
||||
return tg != null && tg.doesTarget();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -336,55 +333,65 @@ public class TargetSelection {
|
||||
* </p>
|
||||
*/
|
||||
public final void clearTargets() {
|
||||
if (this.target != null) {
|
||||
this.target.resetTargets();
|
||||
this.target.calculateStillToDivide(this.ability.getParam("DividedAsYouChoose"), this.getCard(), this.ability);
|
||||
Target tg = getTgt();
|
||||
if (tg != null) {
|
||||
tg.resetTargets();
|
||||
tg.calculateStillToDivide(this.ability.getParam("DividedAsYouChoose"), this.getCard(), this.ability);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* chooseTargets.
|
||||
* </p>
|
||||
*
|
||||
* @return a boolean.
|
||||
*/
|
||||
public final boolean chooseTargets() {
|
||||
Target tgt = getTgt();
|
||||
final boolean canTarget = tgt.doesTarget();
|
||||
final int minTargets = canTarget ? tgt.getMinTargets(getCard(), ability) : 0;
|
||||
final int maxTargets = canTarget ? tgt.getMaxTargets(getCard(), ability) : 0;
|
||||
final int numTargeted = canTarget ? tgt.getNumTargeted() : 0;
|
||||
|
||||
boolean hasEnoughTargets = minTargets == 0 || numTargeted >= minTargets;
|
||||
boolean hasAllTargets = numTargeted == maxTargets && maxTargets > 0;
|
||||
|
||||
// if not enough targets chosen, reset and cancel Ability
|
||||
if (this.bCancel || (this.bTargetingDone && !this.target.isMinTargetsChosen(this.getCard(), this.ability))) {
|
||||
this.bCancel = true;
|
||||
return false;
|
||||
}
|
||||
if (this.bTargetingDone && !hasEnoughTargets) this.bCancel = true;
|
||||
if (this.bCancel) return false;
|
||||
|
||||
|
||||
if (!this.doesTarget()
|
||||
|| this.bTargetingDone && this.target.isMinTargetsChosen(this.getCard(), this.ability)
|
||||
|| this.target.isMaxTargetsChosen(this.getCard(), this.ability)
|
||||
|| this.target.isDividedAsYouChoose() && this.target.getStillToDivide() == 0) {
|
||||
if (!canTarget || this.bTargetingDone && hasEnoughTargets || hasAllTargets || tgt.isDividedAsYouChoose() && tgt.getStillToDivide() == 0) {
|
||||
final AbilitySub abSub = this.ability.getSubAbility();
|
||||
|
||||
if (abSub == null) {
|
||||
// if no more SubAbilities finish targeting
|
||||
if (abSub == null) // if no more SubAbilities finish targeting
|
||||
return true;
|
||||
} else {
|
||||
// Has Sub Ability
|
||||
this.subSelection = new TargetSelection(abSub.getTarget(), abSub);
|
||||
this.subSelection.setRequirements(this.req);
|
||||
this.subSelection.clearTargets();
|
||||
return this.subSelection.chooseTargets();
|
||||
}
|
||||
|
||||
// Has Sub Ability
|
||||
this.subSelection = new TargetChooser(abSub);
|
||||
this.subSelection.clearTargets();
|
||||
return this.subSelection.chooseTargets();
|
||||
}
|
||||
|
||||
if (!this.target.hasCandidates(this.ability, true) && !this.target.isMinTargetsChosen(this.getCard(), this.ability)) {
|
||||
if (!tgt.hasCandidates(this.ability, true) && !hasEnoughTargets) {
|
||||
// Cancel ability if there aren't any valid Candidates
|
||||
this.bCancel = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
this.chooseValidInput();
|
||||
if ( !bCancel )
|
||||
return chooseTargets();
|
||||
|
||||
return false;
|
||||
|
||||
final List<ZoneType> zone = tgt.getZone();
|
||||
final boolean mandatory = tgt.getMandatory() && tgt.hasCandidates(this.ability, true);
|
||||
|
||||
if (zone.size() == 1 && zone.get(0) == ZoneType.Stack) {
|
||||
// If Zone is Stack, the choices are handled slightly differently
|
||||
this.chooseCardFromStack(mandatory);
|
||||
} else {
|
||||
List<Card> validTargets = this.chooseValidInput();
|
||||
if (zone.size() == 1 && zone.get(0) == ZoneType.Battlefield) {
|
||||
InputSelectTargets inp = new InputSelectTargets(validTargets, ability, mandatory);
|
||||
FThreads.setInputAndWait(inp);
|
||||
bCancel = inp.hasCancelled();
|
||||
bTargetingDone = inp.hasPressedOk();
|
||||
} else {
|
||||
this.chooseCardFromList(validTargets, true, mandatory);
|
||||
}
|
||||
}
|
||||
// some inputs choose cards 1-by-1 and need to be called again,
|
||||
// moreover there are sub-abilities that also need targets
|
||||
return chooseTargets();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -416,21 +423,15 @@ public class TargetSelection {
|
||||
* <p>
|
||||
* chooseValidInput.
|
||||
* </p>
|
||||
* @return
|
||||
*/
|
||||
public final void chooseValidInput() {
|
||||
public final List<Card> chooseValidInput() {
|
||||
final Target tgt = this.getTgt();
|
||||
final GameState game = ability.getActivatingPlayer().getGame();
|
||||
final List<ZoneType> zone = tgt.getZone();
|
||||
final boolean mandatory = this.target.getMandatory() ? this.target.hasCandidates(this.ability, true) : false;
|
||||
|
||||
final boolean canTgtStack = zone.contains(ZoneType.Stack);
|
||||
|
||||
if (canTgtStack && (zone.size() == 1)) {
|
||||
// If Zone is Stack, the choices are handled slightly differently
|
||||
this.chooseCardFromStack(mandatory);
|
||||
return;
|
||||
}
|
||||
|
||||
List<Card> choices = CardLists.getTargetableCards(CardLists.getValidCards(Singletons.getModel().getGame().getCardsIn(zone), this.target.getValidTgts(), this.ability.getActivatingPlayer(), this.ability.getSourceCard()), this.ability);
|
||||
List<Card> choices = CardLists.getTargetableCards(CardLists.getValidCards(game.getCardsIn(zone), tgt.getValidTgts(), this.ability.getActivatingPlayer(), this.ability.getSourceCard()), this.ability);
|
||||
if (canTgtStack) {
|
||||
// Since getTargetableCards doesn't have additional checks if one of the Zones is stack
|
||||
// Remove the activating card from targeting itself if its on the Stack
|
||||
@@ -450,7 +451,7 @@ public class TargetSelection {
|
||||
}
|
||||
|
||||
// Remove cards already targeted
|
||||
final ArrayList<Card> targeted = tgt.getTargetCards();
|
||||
final List<Card> targeted = tgt.getTargetCards();
|
||||
for (final Card c : targeted) {
|
||||
if (choices.contains(c)) {
|
||||
choices.remove(c);
|
||||
@@ -486,7 +487,7 @@ public class TargetSelection {
|
||||
}
|
||||
// If all cards must have different controllers
|
||||
if (tgt.isDifferentControllers() && !targeted.isEmpty()) {
|
||||
final List<Player> availableControllers = new ArrayList<Player>(Singletons.getModel().getGame().getPlayers());
|
||||
final List<Player> availableControllers = new ArrayList<Player>(game.getPlayers());
|
||||
for (int i = 0; i < targeted.size(); i++) {
|
||||
availableControllers.remove(targeted.get(i).getController());
|
||||
}
|
||||
@@ -512,20 +513,7 @@ public class TargetSelection {
|
||||
choices.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (!tgt.isUniqueTargets()) {
|
||||
// Previously targeted objects needed to be used for same controller above, but causes problems
|
||||
// if passed through with certain card functionality to inputTargetSpecific so resetting now
|
||||
objects = new ArrayList<Object>();
|
||||
}
|
||||
|
||||
if (zone.contains(ZoneType.Battlefield) && zone.size() == 1) {
|
||||
InputSynchronized inp = new InputSelectTargets(this, choices, objects, true, this.target, this.ability, mandatory);
|
||||
FThreads.setInputAndWait(inp);
|
||||
bTargetingDone = !bCancel;
|
||||
} else {
|
||||
this.chooseCardFromList(choices, true, mandatory);
|
||||
}
|
||||
return choices;
|
||||
} // input_targetValid
|
||||
|
||||
/**
|
||||
@@ -540,92 +528,63 @@ public class TargetSelection {
|
||||
* @param mandatory
|
||||
* a boolean.
|
||||
*/
|
||||
public final void chooseCardFromList(final List<Card> choices, final boolean targeted, final boolean mandatory) {
|
||||
private final void chooseCardFromList(final List<Card> choices, final boolean targeted, final boolean mandatory) {
|
||||
// Send in a list of valid cards, and popup a choice box to target
|
||||
final Card dummy = new Card();
|
||||
dummy.setName("[FINISH TARGETING]");
|
||||
final SpellAbility sa = this.ability;
|
||||
final String message = this.target.getVTSelection();
|
||||
final GameState game = ability.getActivatingPlayer().getGame();
|
||||
|
||||
final Card divBattlefield = new Card();
|
||||
divBattlefield.setName("--CARDS ON BATTLEFIELD:--");
|
||||
final Card divExile = new Card();
|
||||
divExile.setName("--CARDS IN EXILE:--");
|
||||
final Card divGrave = new Card();
|
||||
divGrave.setName("--CARDS IN GRAVEYARD:--");
|
||||
final Card divLibrary = new Card();
|
||||
divLibrary.setName("--CARDS IN LIBRARY:--");
|
||||
final Card divStack = new Card();
|
||||
divStack.setName("--CARDS IN STACK:--");
|
||||
|
||||
List<Card> choicesZoneUnfiltered = choices;
|
||||
final List<Card> crdsBattle = new ArrayList<Card>();
|
||||
final List<Card> crdsExile = new ArrayList<Card>();
|
||||
final List<Card> crdsGrave = new ArrayList<Card>();
|
||||
final List<Card> crdsLibrary = new ArrayList<Card>();
|
||||
final List<Card> crdsStack = new ArrayList<Card>();
|
||||
for (final Card inZone : choicesZoneUnfiltered) {
|
||||
if (Singletons.getModel().getGame().getCardsIn(ZoneType.Battlefield).contains(inZone)) {
|
||||
crdsBattle.add(inZone);
|
||||
} else if (Singletons.getModel().getGame().getCardsIn(ZoneType.Exile).contains(inZone)) {
|
||||
crdsExile.add(inZone);
|
||||
} else if (Singletons.getModel().getGame().getCardsIn(ZoneType.Graveyard).contains(inZone)) {
|
||||
crdsGrave.add(inZone);
|
||||
} else if (Singletons.getModel().getGame().getCardsIn(ZoneType.Library).contains(inZone)) {
|
||||
crdsLibrary.add(inZone);
|
||||
} else if (Singletons.getModel().getGame().getCardsIn(ZoneType.Stack).contains(inZone)) {
|
||||
crdsStack.add(inZone);
|
||||
}
|
||||
for (final Card inZone : choices) {
|
||||
Zone zz = game.getZoneOf(inZone);
|
||||
if (zz.is(ZoneType.Battlefield)) crdsBattle.add(inZone);
|
||||
else if (zz.is(ZoneType.Exile)) crdsExile.add(inZone);
|
||||
else if (zz.is(ZoneType.Graveyard)) crdsGrave.add(inZone);
|
||||
else if (zz.is(ZoneType.Library)) crdsLibrary.add(inZone);
|
||||
else if (zz.is(ZoneType.Stack)) crdsStack.add(inZone);
|
||||
}
|
||||
List<Card> choicesFiltered = new ArrayList<Card>();
|
||||
if (crdsBattle.size() >= 1) {
|
||||
choicesFiltered.add(divBattlefield);
|
||||
List<Object> choicesFiltered = new ArrayList<Object>();
|
||||
if (!crdsBattle.isEmpty()) {
|
||||
choicesFiltered.add("--CARDS ON BATTLEFIELD:--");
|
||||
choicesFiltered.addAll(crdsBattle);
|
||||
crdsBattle.clear();
|
||||
}
|
||||
if (crdsExile.size() >= 1) {
|
||||
choicesFiltered.add(divExile);
|
||||
if (!crdsExile.isEmpty()) {
|
||||
choicesFiltered.add("--CARDS IN EXILE:--");
|
||||
choicesFiltered.addAll(crdsExile);
|
||||
crdsExile.clear();
|
||||
}
|
||||
if (crdsGrave.size() >= 1) {
|
||||
choicesFiltered.add(divGrave);
|
||||
if (!crdsGrave.isEmpty()) {
|
||||
choicesFiltered.add("--CARDS IN GRAVEYARD:--");
|
||||
choicesFiltered.addAll(crdsGrave);
|
||||
crdsGrave.clear();
|
||||
}
|
||||
if (crdsLibrary.size() >= 1) {
|
||||
choicesFiltered.add(divLibrary);
|
||||
if (!crdsLibrary.isEmpty()) {
|
||||
choicesFiltered.add("--CARDS IN LIBRARY:--");
|
||||
choicesFiltered.addAll(crdsLibrary);
|
||||
crdsLibrary.clear();
|
||||
}
|
||||
if (crdsStack.size() >= 1) {
|
||||
choicesFiltered.add(divStack);
|
||||
if (!crdsStack.isEmpty()) {
|
||||
choicesFiltered.add("--CARDS IN STACK:--");
|
||||
choicesFiltered.addAll(crdsStack);
|
||||
crdsStack.clear();
|
||||
}
|
||||
|
||||
final Target tgt = this.getTgt();
|
||||
|
||||
final List<Card> choicesWithDone = choicesFiltered;
|
||||
if (tgt.isMinTargetsChosen(sa.getSourceCard(), sa)) {
|
||||
final String msgDone = "[FINISH TARGETING]";
|
||||
if (this.getTgt().isMinTargetsChosen(this.ability.getSourceCard(), this.ability)) {
|
||||
// is there a more elegant way of doing this?
|
||||
choicesWithDone.add(dummy);
|
||||
choicesFiltered.add(msgDone);
|
||||
}
|
||||
|
||||
final Card check = GuiChoose.oneOrNone(message, choicesWithDone);
|
||||
if (check != null) {
|
||||
final Card c = check;
|
||||
if (!c.equals(divBattlefield) && !c.equals(divExile) && !c.equals(divGrave)
|
||||
&& !c.equals(divLibrary) && !c.equals(divStack)) {
|
||||
if (c.equals(dummy)) {
|
||||
bTargetingDone = true;
|
||||
} else {
|
||||
tgt.addTarget(c);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
final Object chosen = GuiChoose.oneOrNone(getTgt().getVTSelection(), choicesFiltered);
|
||||
if (chosen == null) {
|
||||
this.setCancel(true);
|
||||
return;
|
||||
}
|
||||
if (msgDone.equals(chosen)) {
|
||||
bTargetingDone = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (chosen instanceof Card )
|
||||
this.getTgt().addTarget(chosen);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -636,14 +595,13 @@ public class TargetSelection {
|
||||
* @param mandatory
|
||||
* a boolean.
|
||||
*/
|
||||
public final void chooseCardFromStack(final boolean mandatory) {
|
||||
final Target tgt = this.target;
|
||||
private final void chooseCardFromStack(final boolean mandatory) {
|
||||
final Target tgt = this.getTgt();
|
||||
final String message = tgt.getVTSelection();
|
||||
final TargetSelection select = this;
|
||||
final String doneDummy = "[FINISH TARGETING]";
|
||||
|
||||
// Find what's targetable, then allow human to choose
|
||||
final ArrayList<SpellAbility> choosables = TargetSelection.getTargetableOnStack(this.ability, select.getTgt());
|
||||
final ArrayList<SpellAbility> choosables = getTargetableOnStack();
|
||||
|
||||
final HashMap<String, SpellAbility> map = new HashMap<String, SpellAbility>();
|
||||
|
||||
@@ -657,14 +615,11 @@ public class TargetSelection {
|
||||
map.put(doneDummy, null);
|
||||
}
|
||||
|
||||
String[] choices = new String[map.keySet().size()];
|
||||
choices = map.keySet().toArray(choices);
|
||||
|
||||
if (choices.length == 0) {
|
||||
select.setCancel(true);
|
||||
if (map.isEmpty()) {
|
||||
setCancel(true);
|
||||
} else {
|
||||
final String madeChoice = GuiChoose.oneOrNone(message, choices);
|
||||
|
||||
final String madeChoice = GuiChoose.oneOrNone(message, map.keySet());
|
||||
if (madeChoice != null) {
|
||||
if (madeChoice.equals(doneDummy)) {
|
||||
bTargetingDone = true;
|
||||
@@ -672,7 +627,7 @@ public class TargetSelection {
|
||||
tgt.addTarget(map.get(madeChoice));
|
||||
}
|
||||
} else {
|
||||
select.setCancel(true);
|
||||
setCancel(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -691,15 +646,16 @@ public class TargetSelection {
|
||||
* a {@link forge.card.spellability.Target} object.
|
||||
* @return a {@link java.util.ArrayList} object.
|
||||
*/
|
||||
public static ArrayList<SpellAbility> getTargetableOnStack(final SpellAbility sa, final Target tgt) {
|
||||
private ArrayList<SpellAbility> getTargetableOnStack() {
|
||||
final ArrayList<SpellAbility> choosables = new ArrayList<SpellAbility>();
|
||||
|
||||
for (int i = 0; i < Singletons.getModel().getGame().getStack().size(); i++) {
|
||||
choosables.add(Singletons.getModel().getGame().getStack().peekAbility(i));
|
||||
final GameState game = ability.getActivatingPlayer().getGame();
|
||||
for (int i = 0; i < game.getStack().size(); i++) {
|
||||
choosables.add(game.getStack().peekAbility(i));
|
||||
}
|
||||
|
||||
for (int i = 0; i < choosables.size(); i++) {
|
||||
if (!TargetSelection.matchSpellAbility(sa, choosables.get(i), tgt)) {
|
||||
if (!TargetChooser.matchSpellAbility(ability, choosables.get(i), getTgt())) {
|
||||
choosables.remove(i);
|
||||
}
|
||||
}
|
||||
@@ -753,7 +709,7 @@ public class TargetSelection {
|
||||
boolean result = false;
|
||||
|
||||
for (final Object o : matchTgt.getTargets()) {
|
||||
if (TargetSelection.matchesValid(o, splitTargetRestrictions.split(","), sa)) {
|
||||
if (TargetChooser.matchesValid(o, splitTargetRestrictions.split(","), sa)) {
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
@@ -764,26 +720,10 @@ public class TargetSelection {
|
||||
}
|
||||
}
|
||||
|
||||
if (!TargetSelection.matchesValidSA(topSA, tgt.getValidTgts(), sa)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return topSA.getSourceCard().isValid(tgt.getValidTgts(), sa.getActivatingPlayer(), sa.getSourceCard());
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* matchesValid.
|
||||
* </p>
|
||||
*
|
||||
* @param o
|
||||
* a {@link java.lang.Object} object.
|
||||
* @param valids
|
||||
* an array of {@link java.lang.String} objects.
|
||||
* @param sa
|
||||
* a {@link forge.card.spellability.SpellAbility} object.
|
||||
* @return a boolean.
|
||||
*/
|
||||
|
||||
private static boolean matchesValid(final Object o, final String[] valids, final SpellAbility sa) {
|
||||
final Card srcCard = sa.getSourceCard();
|
||||
final Player activatingPlayer = sa.getActivatingPlayer();
|
||||
@@ -801,24 +741,4 @@ public class TargetSelection {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* matchesValidSA.
|
||||
* </p>
|
||||
*
|
||||
* @param sa
|
||||
* a {@link forge.card.spellability.SpellAbility} object.
|
||||
* @param valids
|
||||
* an array of {@link java.lang.String} objects.
|
||||
* @param source
|
||||
* a {@link forge.card.spellability.SpellAbility} object.
|
||||
* @return a boolean.
|
||||
*/
|
||||
private static boolean matchesValidSA(final SpellAbility sa, final String[] valids, final SpellAbility source) {
|
||||
final Card srcCard = source.getSourceCard();
|
||||
final Player activatingPlayer = source.getActivatingPlayer();
|
||||
final Card c = sa.getSourceCard();
|
||||
return c.isValid(valids, activatingPlayer, srcCard);
|
||||
}
|
||||
}
|
||||
@@ -419,7 +419,7 @@ public class TriggerHandler {
|
||||
|
||||
if (regtrig.isStatic()) {
|
||||
if (wrapperAbility.getActivatingPlayer().isHuman()) {
|
||||
game.getActionPlay().playSpellAbilityNoStack(wrapperAbility.getActivatingPlayer(), wrapperAbility, false);
|
||||
game.getActionPlay().playSpellAbilityNoStack(wrapperAbility.getActivatingPlayer(), wrapperAbility);
|
||||
} else {
|
||||
wrapperAbility.doTrigger(isMandatory, (AIPlayer)wrapperAbility.getActivatingPlayer());
|
||||
ComputerUtil.playNoStack((AIPlayer)wrapperAbility.getActivatingPlayer(), wrapperAbility, game);
|
||||
|
||||
@@ -78,7 +78,7 @@ public class InputMulligan extends InputBase {
|
||||
}
|
||||
|
||||
sb.append("Do you want to Mulligan?");
|
||||
CMatchUI.SINGLETON_INSTANCE.showMessage(sb.toString());
|
||||
showMessage(sb.toString());
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@@ -130,7 +130,7 @@ public class InputMulligan extends InputBase {
|
||||
if (GuiDialog.confirm(c, "Use " + c +"'s ability?")) {
|
||||
// If we ever let the AI memorize cards in the players
|
||||
// hand, this would be a place to do so.
|
||||
game.getActionPlay().playSpellAbilityNoStack(p, effect, false);
|
||||
game.getActionPlay().playSpellAbilityNoStack(p, effect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ import forge.card.mana.ManaCostShard;
|
||||
import forge.card.spellability.SpellAbility;
|
||||
import forge.card.spellability.SpellAbilityRequirements;
|
||||
import forge.card.spellability.Target;
|
||||
import forge.card.spellability.TargetSelection;
|
||||
import forge.card.staticability.StaticAbility;
|
||||
import forge.control.input.InputPayManaSimple;
|
||||
import forge.game.ai.ComputerUtilCard;
|
||||
@@ -73,11 +72,10 @@ public class GameActionPlay {
|
||||
if (sa.getApi() == ApiType.Charm && !sa.isWrapper()) {
|
||||
CharmEffect.makeChoices(sa);
|
||||
}
|
||||
final TargetSelection ts = new TargetSelection(sa.getTarget(), sa);
|
||||
final CostPayment payment = new CostPayment(sa.getPayCosts(), sa);
|
||||
|
||||
final SpellAbilityRequirements req = new SpellAbilityRequirements(sa, ts, payment);
|
||||
req.setFree(true);
|
||||
final SpellAbilityRequirements req = new SpellAbilityRequirements(sa, payment);
|
||||
req.setFree();
|
||||
req.fillRequirements();
|
||||
} else {
|
||||
if (sa.isSpell()) {
|
||||
@@ -383,7 +381,6 @@ public class GameActionPlay {
|
||||
|
||||
// System.out.println("Playing:" + sa.getDescription() + " of " + sa.getSourceCard() + " new = " + newAbility);
|
||||
if (newAbility) {
|
||||
final TargetSelection ts = new TargetSelection(sa.getTarget(), sa);
|
||||
CostPayment payment = null;
|
||||
if (sa.getPayCosts() == null) {
|
||||
payment = new CostPayment(new Cost(sa.getSourceCard(), "0", sa.isAbility()), sa);
|
||||
@@ -391,7 +388,7 @@ public class GameActionPlay {
|
||||
payment = new CostPayment(sa.getPayCosts(), sa);
|
||||
}
|
||||
|
||||
final SpellAbilityRequirements req = new SpellAbilityRequirements(sa, ts, payment);
|
||||
final SpellAbilityRequirements req = new SpellAbilityRequirements(sa, payment);
|
||||
req.fillRequirements();
|
||||
} else {
|
||||
ManaCostBeingPaid manaCost = new ManaCostBeingPaid(sa.getManaCost());
|
||||
@@ -426,20 +423,24 @@ public class GameActionPlay {
|
||||
* @param skipTargeting
|
||||
* a boolean.
|
||||
*/
|
||||
public final void playSpellAbilityNoStack(final Player human, final SpellAbility sa, final boolean skipTargeting) {
|
||||
public final void playSpellAbilityNoStack(final Player human, final SpellAbility sa) {
|
||||
playSpellAbilityNoStack(human, sa, false);
|
||||
}
|
||||
public final void playSpellAbilityNoStack(final Player human, final SpellAbility sa, boolean useOldTargets) {
|
||||
sa.setActivatingPlayer(human);
|
||||
|
||||
if (sa.getPayCosts() != null) {
|
||||
final TargetSelection ts = new TargetSelection(sa.getTarget(), sa);
|
||||
final CostPayment payment = new CostPayment(sa.getPayCosts(), sa);
|
||||
|
||||
if (!sa.isTrigger()) {
|
||||
payment.changeCost();
|
||||
}
|
||||
|
||||
final SpellAbilityRequirements req = new SpellAbilityRequirements(sa, ts, payment);
|
||||
req.setSkipStack(true);
|
||||
req.fillRequirements(skipTargeting);
|
||||
final SpellAbilityRequirements req = new SpellAbilityRequirements(sa, payment);
|
||||
if( useOldTargets )
|
||||
req.setAlreadyTargeted();
|
||||
req.setSkipStack();
|
||||
req.fillRequirements();
|
||||
} else {
|
||||
ManaCostBeingPaid manaCost = new ManaCostBeingPaid(sa.getManaCost());
|
||||
if (sa.getSourceCard().isCopiedSpell() && sa.isSpell()) {
|
||||
|
||||
@@ -42,7 +42,7 @@ import forge.card.spellability.SpellAbility;
|
||||
import forge.card.spellability.SpellAbilityStackInstance;
|
||||
import forge.card.spellability.Target;
|
||||
import forge.card.spellability.TargetChoices;
|
||||
import forge.card.spellability.TargetSelection;
|
||||
import forge.card.spellability.TargetChooser;
|
||||
import forge.card.trigger.Trigger;
|
||||
import forge.card.trigger.TriggerType;
|
||||
import forge.control.input.InputPayManaExecuteCommands;
|
||||
@@ -885,7 +885,7 @@ public class MagicStack extends MyObservable {
|
||||
}
|
||||
else if (o instanceof SpellAbility) {
|
||||
final SpellAbility tgtSA = (SpellAbility) o;
|
||||
invalidTarget = !(TargetSelection.matchSpellAbility(sa, tgtSA, tgt));
|
||||
invalidTarget = !(TargetChooser.matchSpellAbility(sa, tgtSA, tgt));
|
||||
// TODO Remove target?
|
||||
if (invalidTarget) {
|
||||
choices.removeTarget(tgtSA);
|
||||
|
||||
@@ -205,7 +205,6 @@ public final class CEditorConstructed extends ACEditorBase<CardPrinted, Deck> {
|
||||
/**
|
||||
* Switch between the main deck and the sideboard editor.
|
||||
*/
|
||||
@SuppressWarnings("incomplete-switch")
|
||||
public void cycleEditorMode() {
|
||||
int curindex = allSections.indexOf(sectionMode);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user