mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-18 11:48:02 +00:00
Merge pull request #1967 from tool4ever/targeteffects
Forward another PR part to extract targeting checks from effects
This commit is contained in:
@@ -843,4 +843,15 @@ public abstract class SpellAbilityEffect {
|
||||
game.getEndOfTurn().addUntil(until);
|
||||
}
|
||||
}
|
||||
|
||||
public Player getNewChooser(final SpellAbility sa, final Player activator, final Player loser) {
|
||||
// CR 800.4g
|
||||
final PlayerCollection options;
|
||||
if (loser.isOpponentOf(activator)) {
|
||||
options = activator.getOpponents();
|
||||
} else {
|
||||
options = activator.getAllOtherPlayers();
|
||||
}
|
||||
return activator.getController().chooseSingleEntityForEffect(options, sa, Localizer.getInstance().getMessage("lblChoosePlayer") , null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ import forge.game.card.Card;
|
||||
import forge.game.card.CardLists;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.TargetRestrictions;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.util.Lang;
|
||||
import forge.util.Localizer;
|
||||
@@ -36,25 +35,26 @@ public class ActivateAbilityEffect extends SpellAbilityEffect {
|
||||
|
||||
@Override
|
||||
public void resolve(SpellAbility sa) {
|
||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||
final boolean isManaAb = sa.hasParam("ManaAbility");
|
||||
// TODO: improve ai and fix corner cases
|
||||
|
||||
for (final Player p : getTargetPlayers(sa)) {
|
||||
if ((tgt == null) || p.canBeTargetedBy(sa)) {
|
||||
List<Card> list = CardLists.getType(p.getCardsIn(ZoneType.Battlefield), sa.getParamOrDefault("Type", "Card"));
|
||||
for (Card c : list) {
|
||||
List<SpellAbility> possibleAb = Lists.newArrayList(c.getAllPossibleAbilities(p, true));
|
||||
if (isManaAb) {
|
||||
possibleAb.retainAll((FCollection<SpellAbility>)c.getManaAbilities());
|
||||
}
|
||||
if (possibleAb.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
SpellAbility manaAb = p.getController().chooseSingleSpellForEffect(
|
||||
possibleAb, sa, Localizer.getInstance().getMessage("lblChooseManaAbility"), ImmutableMap.of());
|
||||
p.getController().playChosenSpellAbility(manaAb);
|
||||
if (!p.isInGame()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
List<Card> list = CardLists.getType(p.getCardsIn(ZoneType.Battlefield), sa.getParamOrDefault("Type", "Card"));
|
||||
for (Card c : list) {
|
||||
List<SpellAbility> possibleAb = Lists.newArrayList(c.getAllPossibleAbilities(p, true));
|
||||
if (isManaAb) {
|
||||
possibleAb.retainAll((FCollection<SpellAbility>)c.getManaAbilities());
|
||||
}
|
||||
if (possibleAb.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
SpellAbility manaAb = p.getController().chooseSingleSpellForEffect(
|
||||
possibleAb, sa, Localizer.getInstance().getMessage("lblChooseManaAbility"), ImmutableMap.of());
|
||||
p.getController().playChosenSpellAbility(manaAb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package forge.game.ability.effects;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import forge.game.Game;
|
||||
import forge.game.ability.AbilityFactory;
|
||||
import forge.game.ability.AbilityKey;
|
||||
@@ -15,6 +13,7 @@ import forge.game.trigger.Trigger;
|
||||
import forge.game.trigger.TriggerHandler;
|
||||
import forge.game.trigger.TriggerType;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.util.Lang;
|
||||
import forge.util.Localizer;
|
||||
|
||||
public class AddTurnEffect extends SpellAbilityEffect {
|
||||
@@ -24,11 +23,7 @@ public class AddTurnEffect extends SpellAbilityEffect {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
final int numTurns = AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("NumTurns"), sa);
|
||||
|
||||
List<Player> tgtPlayers = getTargetPlayers(sa);
|
||||
|
||||
for (final Player player : tgtPlayers) {
|
||||
sb.append(player).append(" ");
|
||||
}
|
||||
sb.append(Lang.joinHomogenous(getTargetPlayers(sa)));
|
||||
|
||||
sb.append("takes ");
|
||||
sb.append(numTurns > 1 ? numTurns : "an");
|
||||
@@ -45,29 +40,28 @@ public class AddTurnEffect extends SpellAbilityEffect {
|
||||
public void resolve(SpellAbility sa) {
|
||||
final int numTurns = AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("NumTurns"), sa);
|
||||
|
||||
List<Player> tgtPlayers = getTargetPlayers(sa);
|
||||
|
||||
for (final Player p : tgtPlayers) {
|
||||
if (!sa.usesTargeting() || p.canBeTargetedBy(sa)) {
|
||||
for (int i = 0; i < numTurns; i++) {
|
||||
ExtraTurn extra = p.getGame().getPhaseHandler().addExtraTurn(p);
|
||||
if (sa.hasParam("ExtraTurnDelayedTrigger")) {
|
||||
final Trigger delTrig = TriggerHandler.parseTrigger(sa.getSVar(sa.getParam("ExtraTurnDelayedTrigger")), sa.getHostCard(), true);
|
||||
SpellAbility overridingSA = AbilityFactory.getAbility(sa.getSVar(sa.getParam("ExtraTurnDelayedTriggerExcute")), sa.getHostCard());
|
||||
overridingSA.setActivatingPlayer(sa.getActivatingPlayer());
|
||||
delTrig.setOverridingAbility(overridingSA);
|
||||
delTrig.setSpawningAbility(sa.copy(sa.getHostCard(), sa.getActivatingPlayer(), true));
|
||||
extra.addTrigger(delTrig);
|
||||
}
|
||||
if (sa.hasParam("SkipUntap")) {
|
||||
extra.setSkipUntapSA(sa);
|
||||
}
|
||||
if (sa.hasParam("NoSchemes")) {
|
||||
extra.setCantSetSchemesInMotionSA(sa);
|
||||
}
|
||||
if (sa.hasParam("ShowMessage")) {
|
||||
p.getGame().getAction().notifyOfValue(sa, p, Localizer.getInstance().getMessage("lblPlayerTakesExtraTurn", p.toString()), null);
|
||||
}
|
||||
for (final Player p : getTargetPlayers(sa)) {
|
||||
if (!p.isInGame()) {
|
||||
continue;
|
||||
}
|
||||
for (int i = 0; i < numTurns; i++) {
|
||||
ExtraTurn extra = p.getGame().getPhaseHandler().addExtraTurn(p);
|
||||
if (sa.hasParam("ExtraTurnDelayedTrigger")) {
|
||||
final Trigger delTrig = TriggerHandler.parseTrigger(sa.getSVar(sa.getParam("ExtraTurnDelayedTrigger")), sa.getHostCard(), true);
|
||||
SpellAbility overridingSA = AbilityFactory.getAbility(sa.getSVar(sa.getParam("ExtraTurnDelayedTriggerExcute")), sa.getHostCard());
|
||||
overridingSA.setActivatingPlayer(sa.getActivatingPlayer());
|
||||
delTrig.setOverridingAbility(overridingSA);
|
||||
delTrig.setSpawningAbility(sa.copy(sa.getHostCard(), sa.getActivatingPlayer(), true));
|
||||
extra.addTrigger(delTrig);
|
||||
}
|
||||
if (sa.hasParam("SkipUntap")) {
|
||||
extra.setSkipUntapSA(sa);
|
||||
}
|
||||
if (sa.hasParam("NoSchemes")) {
|
||||
extra.setCantSetSchemesInMotionSA(sa);
|
||||
}
|
||||
if (sa.hasParam("ShowMessage")) {
|
||||
p.getGame().getAction().notifyOfValue(sa, p, Localizer.getInstance().getMessage("lblPlayerTakesExtraTurn", p.toString()), null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,10 +27,11 @@ public class BecomeMonarchEffect extends SpellAbilityEffect {
|
||||
final String set = sa.getHostCard().getSetCode();
|
||||
|
||||
for (final Player p : getTargetPlayers(sa)) {
|
||||
if (!sa.usesTargeting() || p.canBeTargetedBy(sa)) {
|
||||
if (p.canBecomeMonarch()) {
|
||||
p.getGame().getAction().becomeMonarch(p, set);
|
||||
}
|
||||
if (!p.isInGame()) {
|
||||
continue;
|
||||
}
|
||||
if (p.canBecomeMonarch()) {
|
||||
p.getGame().getAction().becomeMonarch(p, set);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,17 +34,15 @@ public class BecomesBlockedEffect extends SpellAbilityEffect {
|
||||
final Game game = sa.getActivatingPlayer().getGame();
|
||||
List<Card> blocked = Lists.newArrayList();
|
||||
for (final Card c : getTargetCards(sa)) {
|
||||
if ((!sa.usesTargeting()) || c.canBeTargetedBy(sa)) {
|
||||
game.getCombat().setBlocked(c, true);
|
||||
if (!c.getDamageHistory().getCreatureGotBlockedThisCombat()) {
|
||||
blocked.add(c);
|
||||
final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
|
||||
runParams.put(AbilityKey.Attacker, c);
|
||||
runParams.put(AbilityKey.Blockers, Lists.<Card>newArrayList());
|
||||
runParams.put(AbilityKey.Defender, game.getCombat().getDefenderByAttacker(c));
|
||||
runParams.put(AbilityKey.DefendingPlayer, game.getCombat().getDefenderPlayerByAttacker(c));
|
||||
game.getTriggerHandler().runTrigger(TriggerType.AttackerBlocked, runParams, false);
|
||||
}
|
||||
game.getCombat().setBlocked(c, true);
|
||||
if (!c.getDamageHistory().getCreatureGotBlockedThisCombat()) {
|
||||
blocked.add(c);
|
||||
final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
|
||||
runParams.put(AbilityKey.Attacker, c);
|
||||
runParams.put(AbilityKey.Blockers, Lists.<Card>newArrayList());
|
||||
runParams.put(AbilityKey.Defender, game.getCombat().getDefenderByAttacker(c));
|
||||
runParams.put(AbilityKey.DefendingPlayer, game.getCombat().getDefenderPlayerByAttacker(c));
|
||||
game.getTriggerHandler().runTrigger(TriggerType.AttackerBlocked, runParams, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ import forge.game.event.GameEventCombatChanged;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.SpellAbilityStackInstance;
|
||||
import forge.game.spellability.TargetRestrictions;
|
||||
import forge.util.CardTranslation;
|
||||
import forge.util.Localizer;
|
||||
import forge.util.collect.FCollection;
|
||||
@@ -42,7 +41,6 @@ public class ChangeCombatantsEffect extends SpellAbilityEffect {
|
||||
boolean isCombatChanged = false;
|
||||
final Player activator = sa.getActivatingPlayer();
|
||||
final Game game = activator.getGame();
|
||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||
// TODO: may expand this effect for defined blocker (False Orders, General Jarkeld, Sorrow's Path, Ydwen Efreet)
|
||||
for (final Card c : getTargetCards(sa)) {
|
||||
String cardString = CardTranslation.getTranslatedName(c.getName()) + " (" + c.getId() + ")";
|
||||
@@ -51,38 +49,37 @@ public class ChangeCombatantsEffect extends SpellAbilityEffect {
|
||||
Localizer.getInstance().getMessage("lblChangeCombatantOption", cardString), null)) {
|
||||
continue;
|
||||
}
|
||||
if ((tgt == null) || c.canBeTargetedBy(sa)) {
|
||||
final Combat combat = game.getCombat();
|
||||
final GameEntity originalDefender = combat.getDefenderByAttacker(c);
|
||||
final FCollection<GameEntity> defs = new FCollection<>();
|
||||
defs.addAll(sa.hasParam("PlayerOnly") ? combat.getDefendingPlayers() : combat.getDefenders());
|
||||
|
||||
String title = Localizer.getInstance().getMessage("lblChooseDefenderToAttackWithCard", cardString);
|
||||
Map<String, Object> params = Maps.newHashMap();
|
||||
params.put("Attacker", c);
|
||||
final Combat combat = game.getCombat();
|
||||
final GameEntity originalDefender = combat.getDefenderByAttacker(c);
|
||||
final FCollection<GameEntity> defs = new FCollection<>();
|
||||
defs.addAll(sa.hasParam("PlayerOnly") ? combat.getDefendingPlayers() : combat.getDefenders());
|
||||
|
||||
final GameEntity defender = sa.getActivatingPlayer().getController().chooseSingleEntityForEffect(defs, sa, title, false, params);
|
||||
if (originalDefender != null && !originalDefender.equals(defender)) {
|
||||
AttackingBand ab = combat.getBandOfAttacker(c);
|
||||
if (ab != null) {
|
||||
combat.unregisterAttacker(c, ab);
|
||||
ab.removeAttacker(c);
|
||||
}
|
||||
combat.addAttacker(c, defender);
|
||||
// retarget triggers to the new defender (e.g. Ulamog, Ceaseless Hunger + Portal Mage)
|
||||
for (SpellAbilityStackInstance si : game.getStack()) {
|
||||
if (si.isTrigger() && c.equals(si.getSourceCard())
|
||||
&& si.getTriggeringObject(AbilityKey.Attacker) != null) {
|
||||
si.addTriggeringObject(AbilityKey.OriginalDefender, originalDefender);
|
||||
if (defender instanceof Player) {
|
||||
si.updateTriggeringObject(AbilityKey.DefendingPlayer, defender);
|
||||
} else if (defender instanceof Card) {
|
||||
si.updateTriggeringObject(AbilityKey.DefendingPlayer, ((Card)defender).getController());
|
||||
}
|
||||
String title = Localizer.getInstance().getMessage("lblChooseDefenderToAttackWithCard", cardString);
|
||||
Map<String, Object> params = Maps.newHashMap();
|
||||
params.put("Attacker", c);
|
||||
|
||||
final GameEntity defender = activator.getController().chooseSingleEntityForEffect(defs, sa, title, false, params);
|
||||
if (originalDefender != null && !originalDefender.equals(defender)) {
|
||||
AttackingBand ab = combat.getBandOfAttacker(c);
|
||||
if (ab != null) {
|
||||
combat.unregisterAttacker(c, ab);
|
||||
ab.removeAttacker(c);
|
||||
}
|
||||
combat.addAttacker(c, defender);
|
||||
// retarget triggers to the new defender (e.g. Ulamog, Ceaseless Hunger + Portal Mage)
|
||||
for (SpellAbilityStackInstance si : game.getStack()) {
|
||||
if (si.isTrigger() && c.equals(si.getSourceCard())
|
||||
&& si.getTriggeringObject(AbilityKey.Attacker) != null) {
|
||||
si.addTriggeringObject(AbilityKey.OriginalDefender, originalDefender);
|
||||
if (defender instanceof Player) {
|
||||
si.updateTriggeringObject(AbilityKey.DefendingPlayer, defender);
|
||||
} else if (defender instanceof Card) {
|
||||
si.updateTriggeringObject(AbilityKey.DefendingPlayer, ((Card)defender).getController());
|
||||
}
|
||||
}
|
||||
isCombatChanged = true;
|
||||
}
|
||||
isCombatChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -537,15 +537,13 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
if (gameCard == null || !tgtC.equalsWithTimestamp(gameCard) || gameCard.isPhasedOut()) {
|
||||
continue;
|
||||
}
|
||||
if (sa.usesTargeting() && !gameCard.canBeTargetedBy(sa)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sa.hasParam("RememberLKI")) {
|
||||
hostCard.addRemembered(CardUtil.getLKICopy(gameCard));
|
||||
}
|
||||
|
||||
final String prompt = TextUtil.concatWithSpace(Localizer.getInstance().getMessage("lblDoYouWantMoveTargetFromOriToDest", CardTranslation.getTranslatedName(gameCard.getName()), Lang.joinHomogenous(origin, ZoneType.Accessors.GET_TRANSLATED_NAME), destination.getTranslatedName()));
|
||||
if (optional && !chooser.getController().confirmAction(sa, null, prompt, null) )
|
||||
if (optional && !chooser.getController().confirmAction(sa, null, prompt, null))
|
||||
continue;
|
||||
|
||||
final Zone originZone = game.getZoneOf(gameCard);
|
||||
|
||||
@@ -22,7 +22,6 @@ import forge.game.card.CardPredicates.Presets;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerActionConfirmMode;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.TargetRestrictions;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.util.Aggregates;
|
||||
import forge.util.Lang;
|
||||
@@ -61,7 +60,6 @@ public class ChooseCardEffect extends SpellAbilityEffect {
|
||||
final Game game = activator.getGame();
|
||||
CardCollection chosen = new CardCollection();
|
||||
|
||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||
final List<Player> tgtPlayers = getTargetPlayers(sa);
|
||||
|
||||
List<ZoneType> choiceZone = Lists.newArrayList(ZoneType.Battlefield);
|
||||
@@ -101,7 +99,10 @@ public class ChooseCardEffect extends SpellAbilityEffect {
|
||||
return;
|
||||
}
|
||||
|
||||
for (final Player p : tgtPlayers) {
|
||||
for (Player p : tgtPlayers) {
|
||||
if (!p.isInGame()) {
|
||||
p = getNewChooser(sa, activator, p);
|
||||
}
|
||||
boolean dontRevealToOwner = true;
|
||||
if (sa.hasParam("EachBasicType")) {
|
||||
// Get all lands,
|
||||
@@ -212,51 +213,49 @@ public class ChooseCardEffect extends SpellAbilityEffect {
|
||||
// Targeted player (p) chooses N creatures that belongs to them
|
||||
CardCollection tgtPlayerCtrl = CardLists.filterControlledBy(choices, p);
|
||||
chosen.addAll(p.getController().chooseCardsForEffect(tgtPlayerCtrl, sa, title + " " + "you control", minAmount, validAmount,
|
||||
!sa.hasParam("Mandatory"), null));
|
||||
!sa.hasParam("Mandatory"), null));
|
||||
// Targeted player (p) chooses N creatures that don't belong to them
|
||||
CardCollection notTgtPlayerCtrl = new CardCollection(choices);
|
||||
notTgtPlayerCtrl.removeAll(tgtPlayerCtrl);
|
||||
chosen.addAll(p.getController().chooseCardsForEffect(notTgtPlayerCtrl, sa, title + " " + "you don't control", minAmount, validAmount,
|
||||
!sa.hasParam("Mandatory"), null));
|
||||
!sa.hasParam("Mandatory"), null));
|
||||
|
||||
} else if ((tgt == null) || p.canBeTargetedBy(sa)) {
|
||||
if (sa.hasParam("AtRandom") && !choices.isEmpty()) {
|
||||
// don't pass FCollection for direct modification, the Set part would get messed up
|
||||
chosen = new CardCollection(Aggregates.random(choices, validAmount));
|
||||
dontRevealToOwner = false;
|
||||
} else if (sa.hasParam("AtRandom") && !choices.isEmpty()) {
|
||||
// don't pass FCollection for direct modification, the Set part would get messed up
|
||||
chosen = new CardCollection(Aggregates.random(choices, validAmount));
|
||||
dontRevealToOwner = false;
|
||||
} else {
|
||||
String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChooseaCard") + " ";
|
||||
if (sa.hasParam ("ChoiceTitleAppend")) {
|
||||
String tag = "";
|
||||
String value = sa.getParam("ChoiceTitleAppend");
|
||||
if (value.startsWith("Defined ")) {
|
||||
tag = AbilityUtils.getDefinedPlayers(host, value.substring(8), sa).toString();
|
||||
} else if (value.equals("ChosenType")) {
|
||||
tag = host.getChosenType();
|
||||
}
|
||||
if (!tag.equals("")) {
|
||||
title = title + " (" + tag +")";
|
||||
}
|
||||
}
|
||||
if (sa.hasParam("QuasiLibrarySearch")) {
|
||||
final Player searched = AbilityUtils.getDefinedPlayers(host,
|
||||
sa.getParam("QuasiLibrarySearch"), sa).get(0);
|
||||
final int fetchNum = Math.min(searched.getCardsIn(ZoneType.Library).size(), 4);
|
||||
CardCollectionView shown = !p.hasKeyword("LimitSearchLibrary")
|
||||
? searched.getCardsIn(ZoneType.Library) : searched.getCardsIn(ZoneType.Library, fetchNum);
|
||||
DelayedReveal delayedReveal = new DelayedReveal(shown, ZoneType.Library, PlayerView.get(searched),
|
||||
CardTranslation.getTranslatedName(host.getName()) + " - " +
|
||||
Localizer.getInstance().getMessage("lblLookingCardIn") + " ");
|
||||
Card choice = p.getController().chooseSingleEntityForEffect(choices, delayedReveal, sa, title,
|
||||
!sa.hasParam("Mandatory"), p, null);
|
||||
if (choice == null) {
|
||||
return;
|
||||
}
|
||||
chosen.add(choice);
|
||||
} else {
|
||||
String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChooseaCard") + " ";
|
||||
if (sa.hasParam ("ChoiceTitleAppend")) {
|
||||
String tag = "";
|
||||
String value = sa.getParam("ChoiceTitleAppend");
|
||||
if (value.startsWith("Defined ")) {
|
||||
tag = AbilityUtils.getDefinedPlayers(host, value.substring(8), sa).toString();
|
||||
} else if (value.equals("ChosenType")) {
|
||||
tag = host.getChosenType();
|
||||
}
|
||||
if (!tag.equals("")) {
|
||||
title = title + " (" + tag +")";
|
||||
}
|
||||
}
|
||||
if (sa.hasParam("QuasiLibrarySearch")) {
|
||||
final Player searched = AbilityUtils.getDefinedPlayers(host,
|
||||
sa.getParam("QuasiLibrarySearch"), sa).get(0);
|
||||
final int fetchNum = Math.min(searched.getCardsIn(ZoneType.Library).size(), 4);
|
||||
CardCollectionView shown = !p.hasKeyword("LimitSearchLibrary")
|
||||
? searched.getCardsIn(ZoneType.Library) : searched.getCardsIn(ZoneType.Library, fetchNum);
|
||||
DelayedReveal delayedReveal = new DelayedReveal(shown, ZoneType.Library, PlayerView.get(searched),
|
||||
CardTranslation.getTranslatedName(host.getName()) + " - " +
|
||||
Localizer.getInstance().getMessage("lblLookingCardIn") + " ");
|
||||
Card choice = p.getController().chooseSingleEntityForEffect(choices, delayedReveal, sa, title,
|
||||
!sa.hasParam("Mandatory"), p, null);
|
||||
if (choice == null) {
|
||||
return;
|
||||
}
|
||||
chosen.add(choice);
|
||||
} else {
|
||||
chosen.addAll(p.getController().chooseCardsForEffect(choices, sa, title, minAmount, validAmount,
|
||||
!sa.hasParam("Mandatory"), null));
|
||||
}
|
||||
chosen.addAll(p.getController().chooseCardsForEffect(choices, sa, title, minAmount, validAmount,
|
||||
!sa.hasParam("Mandatory"), null));
|
||||
}
|
||||
}
|
||||
if (sa.hasParam("Reveal") && !sa.hasParam("SecretlyChoose")) {
|
||||
|
||||
@@ -19,7 +19,6 @@ import forge.game.card.CardCollection;
|
||||
import forge.game.card.CardLists;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.TargetRestrictions;
|
||||
import forge.util.Aggregates;
|
||||
import forge.util.Localizer;
|
||||
|
||||
@@ -41,9 +40,6 @@ public class ChooseCardNameEffect extends SpellAbilityEffect {
|
||||
public void resolve(SpellAbility sa) {
|
||||
final Card host = sa.getHostCard();
|
||||
|
||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||
final List<Player> tgtPlayers = getTargetPlayers(sa);
|
||||
|
||||
String valid = "Card";
|
||||
String validDesc = null;
|
||||
String message = null;
|
||||
@@ -68,102 +64,103 @@ public class ChooseCardNameEffect extends SpellAbilityEffect {
|
||||
}
|
||||
}
|
||||
|
||||
for (final Player p : tgtPlayers) {
|
||||
if ((tgt == null) || p.canBeTargetedBy(sa)) {
|
||||
String chosen = "";
|
||||
//This section was used for Momir Avatar, which no longer uses it - commented out 7/28/2021
|
||||
//if (randomChoice) {
|
||||
//String numericAmount = "X";
|
||||
//final int validAmount = StringUtils.isNumeric(numericAmount) ? Integer.parseInt(numericAmount) :
|
||||
// AbilityUtils.calculateAmount(host, numericAmount, sa);
|
||||
// Momir needs PaperCard
|
||||
//Collection<PaperCard> cards = StaticData.instance().getCommonCards().getUniqueCards();
|
||||
//Predicate<PaperCard> cpp = Predicates.and(
|
||||
// Predicates.compose(CardRulesPredicates.Presets.IS_CREATURE, PaperCard.FN_GET_RULES),
|
||||
// Predicates.compose(CardRulesPredicates.cmc(ComparableOp.EQUALS, validAmount), PaperCard.FN_GET_RULES));
|
||||
//cards = Lists.newArrayList(Iterables.filter(cards, cpp));
|
||||
//if (!cards.isEmpty()) { chosen = Aggregates.random(cards).getName();
|
||||
//} else {
|
||||
// chosen = "";
|
||||
//}
|
||||
if (chooseFromDefined) {
|
||||
CardCollection choices = AbilityUtils.getDefinedCards(host, sa.getParam("ChooseFromDefinedCards"), sa);
|
||||
choices = CardLists.getValidCards(choices, valid, host.getController(), host, sa);
|
||||
List<ICardFace> faces = new ArrayList<>();
|
||||
// get Card
|
||||
for (final Card c : choices) {
|
||||
final CardRules rules = c.getRules();
|
||||
if (faces.contains(rules.getMainPart()))
|
||||
continue;
|
||||
faces.add(rules.getMainPart());
|
||||
// Alhammarret only allows Split for other faces
|
||||
if (rules.getSplitType() == CardSplitType.Split) {
|
||||
faces.add(rules.getOtherPart());
|
||||
}
|
||||
for (final Player p : getTargetPlayers(sa)) {
|
||||
if (!p.isInGame()) {
|
||||
continue;
|
||||
}
|
||||
String chosen = "";
|
||||
//This section was used for Momir Avatar, which no longer uses it - commented out 7/28/2021
|
||||
//if (randomChoice) {
|
||||
//String numericAmount = "X";
|
||||
//final int validAmount = StringUtils.isNumeric(numericAmount) ? Integer.parseInt(numericAmount) :
|
||||
// AbilityUtils.calculateAmount(host, numericAmount, sa);
|
||||
// Momir needs PaperCard
|
||||
//Collection<PaperCard> cards = StaticData.instance().getCommonCards().getUniqueCards();
|
||||
//Predicate<PaperCard> cpp = Predicates.and(
|
||||
// Predicates.compose(CardRulesPredicates.Presets.IS_CREATURE, PaperCard.FN_GET_RULES),
|
||||
// Predicates.compose(CardRulesPredicates.cmc(ComparableOp.EQUALS, validAmount), PaperCard.FN_GET_RULES));
|
||||
//cards = Lists.newArrayList(Iterables.filter(cards, cpp));
|
||||
//if (!cards.isEmpty()) { chosen = Aggregates.random(cards).getName();
|
||||
//} else {
|
||||
// chosen = "";
|
||||
//}
|
||||
if (chooseFromDefined) {
|
||||
CardCollection choices = AbilityUtils.getDefinedCards(host, sa.getParam("ChooseFromDefinedCards"), sa);
|
||||
choices = CardLists.getValidCards(choices, valid, host.getController(), host, sa);
|
||||
List<ICardFace> faces = new ArrayList<>();
|
||||
// get Card
|
||||
for (final Card c : choices) {
|
||||
final CardRules rules = c.getRules();
|
||||
if (faces.contains(rules.getMainPart()))
|
||||
continue;
|
||||
faces.add(rules.getMainPart());
|
||||
// Alhammarret only allows Split for other faces
|
||||
if (rules.getSplitType() == CardSplitType.Split) {
|
||||
faces.add(rules.getOtherPart());
|
||||
}
|
||||
Collections.sort(faces);
|
||||
chosen = p.getController().chooseCardName(sa, faces, message);
|
||||
} else if (chooseFromList) {
|
||||
String [] names = sa.getParam("ChooseFromList").split(",");
|
||||
List<ICardFace> faces = new ArrayList<>();
|
||||
for (String name : names) {
|
||||
// Cardnames that include "," must use ";" instead in ChooseFromList$ (i.e. Tovolar; Dire Overlord)
|
||||
name = name.replace(";", ",");
|
||||
faces.add(StaticData.instance().getCommonCards().getFaceByName(name));
|
||||
}
|
||||
if (randomChoice) {
|
||||
chosen = Aggregates.random(faces).getName();
|
||||
} else {
|
||||
chosen = p.getController().chooseCardName(sa, faces, message);
|
||||
}
|
||||
} else if (chooseFromOneTimeList) {
|
||||
String [] names = sa.getParam("ChooseFromOneTimeList").split(",");
|
||||
List<ICardFace> faces = new ArrayList<>();
|
||||
for (String name : names) {
|
||||
faces.add(StaticData.instance().getCommonCards().getFaceByName(name));
|
||||
}
|
||||
chosen = p.getController().chooseCardName(sa, faces, message);
|
||||
|
||||
// Remove chosen Name from List
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String name : names) {
|
||||
if (chosen.equals(name)) continue;
|
||||
if (sb.length() > 0) sb.append(',');
|
||||
sb.append(name);
|
||||
}
|
||||
sa.putParam("ChooseFromOneTimeList", sb.toString());
|
||||
}
|
||||
Collections.sort(faces);
|
||||
chosen = p.getController().chooseCardName(sa, faces, message);
|
||||
} else if (chooseFromList) {
|
||||
String [] names = sa.getParam("ChooseFromList").split(",");
|
||||
List<ICardFace> faces = new ArrayList<>();
|
||||
for (String name : names) {
|
||||
// Cardnames that include "," must use ";" instead in ChooseFromList$ (i.e. Tovolar; Dire Overlord)
|
||||
name = name.replace(";", ",");
|
||||
faces.add(StaticData.instance().getCommonCards().getFaceByName(name));
|
||||
}
|
||||
if (randomChoice) {
|
||||
chosen = Aggregates.random(faces).getName();
|
||||
} else {
|
||||
// use CardFace because you might name a alternate names
|
||||
Predicate<ICardFace> cpp = Predicates.alwaysTrue();
|
||||
if (sa.hasParam("ValidCards")) {
|
||||
//Calculating/replacing this must happen before running valid in CardFacePredicates
|
||||
if (valid.contains("ManaCost=")) {
|
||||
if (valid.contains("ManaCost=Equipped")) {
|
||||
String s = host.getEquipping().getManaCost().getShortString();
|
||||
valid = valid.replace("=Equipped", s);
|
||||
} else if (valid.contains("ManaCost=Imprinted")) {
|
||||
String s = host.getImprintedCards().getFirst().getManaCost().getShortString();
|
||||
valid = valid.replace("=Imprinted", s);
|
||||
}
|
||||
}
|
||||
cpp = CardFacePredicates.valid(valid);
|
||||
}
|
||||
if (randomChoice) {
|
||||
final Iterable<ICardFace> cardsFromDb = StaticData.instance().getCommonCards().getAllFaces();
|
||||
final List<ICardFace> cards = Lists.newArrayList(Iterables.filter(cardsFromDb, cpp));
|
||||
chosen = Aggregates.random(cards).getName();
|
||||
} else {
|
||||
chosen = p.getController().chooseCardName(sa, cpp, valid, message);
|
||||
}
|
||||
chosen = p.getController().chooseCardName(sa, faces, message);
|
||||
}
|
||||
} else if (chooseFromOneTimeList) {
|
||||
String [] names = sa.getParam("ChooseFromOneTimeList").split(",");
|
||||
List<ICardFace> faces = new ArrayList<>();
|
||||
for (String name : names) {
|
||||
faces.add(StaticData.instance().getCommonCards().getFaceByName(name));
|
||||
}
|
||||
chosen = p.getController().chooseCardName(sa, faces, message);
|
||||
|
||||
host.setNamedCard(chosen);
|
||||
if (!randomChoice) {
|
||||
p.setNamedCard(chosen);
|
||||
// Remove chosen Name from List
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String name : names) {
|
||||
if (chosen.equals(name)) continue;
|
||||
if (sb.length() > 0) sb.append(',');
|
||||
sb.append(name);
|
||||
}
|
||||
if (sa.hasParam("NoteFor")) {
|
||||
p.addNoteForName(sa.getParam("NoteFor"), "Name:" + chosen);
|
||||
sa.putParam("ChooseFromOneTimeList", sb.toString());
|
||||
} else {
|
||||
// use CardFace because you might name a alternate names
|
||||
Predicate<ICardFace> cpp = Predicates.alwaysTrue();
|
||||
if (sa.hasParam("ValidCards")) {
|
||||
//Calculating/replacing this must happen before running valid in CardFacePredicates
|
||||
if (valid.contains("ManaCost=")) {
|
||||
if (valid.contains("ManaCost=Equipped")) {
|
||||
String s = host.getEquipping().getManaCost().getShortString();
|
||||
valid = valid.replace("=Equipped", s);
|
||||
} else if (valid.contains("ManaCost=Imprinted")) {
|
||||
String s = host.getImprintedCards().getFirst().getManaCost().getShortString();
|
||||
valid = valid.replace("=Imprinted", s);
|
||||
}
|
||||
}
|
||||
cpp = CardFacePredicates.valid(valid);
|
||||
}
|
||||
if (randomChoice) {
|
||||
final Iterable<ICardFace> cardsFromDb = StaticData.instance().getCommonCards().getAllFaces();
|
||||
final List<ICardFace> cards = Lists.newArrayList(Iterables.filter(cardsFromDb, cpp));
|
||||
chosen = Aggregates.random(cards).getName();
|
||||
} else {
|
||||
chosen = p.getController().chooseCardName(sa, cpp, valid, message);
|
||||
}
|
||||
}
|
||||
|
||||
host.setNamedCard(chosen);
|
||||
if (!randomChoice) {
|
||||
p.setNamedCard(chosen);
|
||||
}
|
||||
if (sa.hasParam("NoteFor")) {
|
||||
p.addNoteForName(sa.getParam("NoteFor"), "Name:" + chosen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import forge.game.ability.SpellAbilityEffect;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.TargetRestrictions;
|
||||
import forge.util.Aggregates;
|
||||
import forge.util.Lang;
|
||||
import forge.util.Localizer;
|
||||
@@ -49,48 +48,45 @@ public class ChooseColorEffect extends SpellAbilityEffect {
|
||||
}
|
||||
}
|
||||
|
||||
final List<Player> tgtPlayers = getTargetPlayers(sa);
|
||||
|
||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||
|
||||
for (final Player p : tgtPlayers) {
|
||||
if ((tgt == null) || p.canBeTargetedBy(sa)) {
|
||||
List<String> chosenColors = new ArrayList<>();
|
||||
int cntMin = sa.hasParam("TwoColors") ? 2 : 1;
|
||||
int cntMax = sa.hasParam("TwoColors") ? 2 : sa.hasParam("OrColors") ? colorChoices.size() : 1;
|
||||
String prompt = null;
|
||||
if (cntMax == 1) {
|
||||
prompt = Localizer.getInstance().getMessage("lblChooseAColor");
|
||||
} else {
|
||||
if (cntMax > cntMin) {
|
||||
if (cntMax >= MagicColor.NUMBER_OR_COLORS) {
|
||||
prompt = Localizer.getInstance().getMessage("lblAtLastChooseNumColors", Lang.getNumeral(cntMin));
|
||||
} else {
|
||||
prompt = Localizer.getInstance().getMessage("lblChooseSpecifiedRangeColors", Lang.getNumeral(cntMin), Lang.getNumeral(cntMax));
|
||||
}
|
||||
} else {
|
||||
prompt = Localizer.getInstance().getMessage("lblChooseNColors", Lang.getNumeral(cntMax));
|
||||
}
|
||||
}
|
||||
Player noNotify = p;
|
||||
if (sa.hasParam("Random")) {
|
||||
String choice;
|
||||
for (int i=0; i<cntMin; i++) {
|
||||
choice = Aggregates.random(colorChoices);
|
||||
colorChoices.remove(choice);
|
||||
chosenColors.add(choice);
|
||||
}
|
||||
noNotify = null;
|
||||
} else {
|
||||
chosenColors = p.getController().chooseColors(prompt, sa, cntMin, cntMax, colorChoices);
|
||||
}
|
||||
if (chosenColors.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
card.setChosenColors(chosenColors);
|
||||
chosenColors = chosenColors.stream().map(DeckRecognizer::getLocalisedMagicColorName).collect(Collectors.toList());
|
||||
p.getGame().getAction().notifyOfValue(sa, p, Lang.joinHomogenous(chosenColors), noNotify);
|
||||
for (Player p : getTargetPlayers(sa)) {
|
||||
if (!p.isInGame()) {
|
||||
p = getNewChooser(sa, sa.getActivatingPlayer(), p);
|
||||
}
|
||||
List<String> chosenColors = new ArrayList<>();
|
||||
int cntMin = sa.hasParam("TwoColors") ? 2 : 1;
|
||||
int cntMax = sa.hasParam("TwoColors") ? 2 : sa.hasParam("OrColors") ? colorChoices.size() : 1;
|
||||
String prompt = null;
|
||||
if (cntMax == 1) {
|
||||
prompt = Localizer.getInstance().getMessage("lblChooseAColor");
|
||||
} else {
|
||||
if (cntMax > cntMin) {
|
||||
if (cntMax >= MagicColor.NUMBER_OR_COLORS) {
|
||||
prompt = Localizer.getInstance().getMessage("lblAtLastChooseNumColors", Lang.getNumeral(cntMin));
|
||||
} else {
|
||||
prompt = Localizer.getInstance().getMessage("lblChooseSpecifiedRangeColors", Lang.getNumeral(cntMin), Lang.getNumeral(cntMax));
|
||||
}
|
||||
} else {
|
||||
prompt = Localizer.getInstance().getMessage("lblChooseNColors", Lang.getNumeral(cntMax));
|
||||
}
|
||||
}
|
||||
Player noNotify = p;
|
||||
if (sa.hasParam("Random")) {
|
||||
String choice;
|
||||
for (int i=0; i<cntMin; i++) {
|
||||
choice = Aggregates.random(colorChoices);
|
||||
colorChoices.remove(choice);
|
||||
chosenColors.add(choice);
|
||||
}
|
||||
noNotify = null;
|
||||
} else {
|
||||
chosenColors = p.getController().chooseColors(prompt, sa, cntMin, cntMax, colorChoices);
|
||||
}
|
||||
if (chosenColors.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
card.setChosenColors(chosenColors);
|
||||
chosenColors = chosenColors.stream().map(DeckRecognizer::getLocalisedMagicColorName).collect(Collectors.toList());
|
||||
p.getGame().getAction().notifyOfValue(sa, p, Lang.joinHomogenous(chosenColors), noNotify);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,12 +30,13 @@ public class ChooseEvenOddEffect extends SpellAbilityEffect {
|
||||
final Card card = sa.getHostCard();
|
||||
|
||||
for (final Player p : getTargetPlayers(sa)) {
|
||||
if ((!sa.usesTargeting()) || p.canBeTargetedBy(sa)) {
|
||||
EvenOdd chosen = p.getController().chooseBinary(sa, "odd or even", BinaryChoiceType.OddsOrEvens) ? EvenOdd.Odd : EvenOdd.Even;
|
||||
card.setChosenEvenOdd(chosen);
|
||||
if (sa.hasParam("Notify")) {
|
||||
p.getGame().getAction().notifyOfValue(sa, card, Localizer.getInstance().getMessage("lblPlayerPickedChosen", p.getName(), chosen), p);
|
||||
}
|
||||
if (!p.isInGame()) {
|
||||
continue;
|
||||
}
|
||||
EvenOdd chosen = p.getController().chooseBinary(sa, "odd or even", BinaryChoiceType.OddsOrEvens) ? EvenOdd.Odd : EvenOdd.Even;
|
||||
card.setChosenEvenOdd(chosen);
|
||||
if (sa.hasParam("Notify")) {
|
||||
p.getGame().getAction().notifyOfValue(sa, card, Localizer.getInstance().getMessage("lblPlayerPickedChosen", p.getName(), chosen), p);
|
||||
}
|
||||
}
|
||||
card.updateStateForView();
|
||||
|
||||
@@ -43,9 +43,10 @@ public class ChooseGenericEffect extends SpellAbilityEffect {
|
||||
final SpellAbility fallback = sa.getAdditionalAbility("FallbackAbility");
|
||||
final int amount = AbilityUtils.calculateAmount(host, sa.getParamOrDefault("ChoiceAmount", "1"), sa);
|
||||
|
||||
final List<Player> tgtPlayers = getDefinedPlayersOrTargeted(sa);
|
||||
|
||||
for (final Player p : tgtPlayers) {
|
||||
for (Player p : getDefinedPlayersOrTargeted(sa)) {
|
||||
if (!p.isInGame()) {
|
||||
p = getNewChooser(sa, sa.getActivatingPlayer(), p);
|
||||
}
|
||||
// determine if any of the choices are not valid
|
||||
List<SpellAbility> saToRemove = Lists.newArrayList();
|
||||
|
||||
@@ -62,10 +63,6 @@ public class ChooseGenericEffect extends SpellAbilityEffect {
|
||||
}
|
||||
abilities.removeAll(saToRemove);
|
||||
|
||||
if (sa.usesTargeting() && sa.getTargets().contains(p) && !p.canBeTargetedBy(sa)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
List<SpellAbility> chosenSAs = Lists.newArrayList();
|
||||
String prompt = sa.getParamOrDefault("ChoicePrompt", "Choose");
|
||||
boolean random = false;
|
||||
|
||||
@@ -12,7 +12,6 @@ import forge.game.ability.SpellAbilityEffect;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.TargetRestrictions;
|
||||
import forge.util.Localizer;
|
||||
import forge.util.MyRandom;
|
||||
|
||||
@@ -46,35 +45,34 @@ public class ChooseNumberEffect extends SpellAbilityEffect {
|
||||
final String sMax = sa.getParamOrDefault("Max", "99");
|
||||
final int max = AbilityUtils.calculateAmount(card, sMax, sa);
|
||||
|
||||
final List<Player> tgtPlayers = getTargetPlayers(sa);
|
||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||
final Map<Player, Integer> chooseMap = Maps.newHashMap();
|
||||
|
||||
for (final Player p : tgtPlayers) {
|
||||
if ((tgt == null) || p.canBeTargetedBy(sa)) {
|
||||
int chosen;
|
||||
if (random) {
|
||||
chosen = MyRandom.getRandom().nextInt((max - min) + 1) + min;
|
||||
//TODO more useful notify for RepeatEach -> ChooseNumber with random
|
||||
p.getGame().getAction().notifyOfValue(sa, p, Integer.toString(chosen), null);
|
||||
for (final Player p : getTargetPlayers(sa)) {
|
||||
if (!p.isInGame()) {
|
||||
continue;
|
||||
}
|
||||
int chosen;
|
||||
if (random) {
|
||||
chosen = MyRandom.getRandom().nextInt((max - min) + 1) + min;
|
||||
//TODO more useful notify for RepeatEach -> ChooseNumber with random
|
||||
p.getGame().getAction().notifyOfValue(sa, p, Integer.toString(chosen), null);
|
||||
} else {
|
||||
String title = sa.hasParam("ListTitle") ? sa.getParam("ListTitle") : Localizer.getInstance().getMessage("lblChooseNumber");
|
||||
if (anyNumber) {
|
||||
Integer value = p.getController().announceRequirements(sa, title);
|
||||
chosen = value == null ? 0 : value;
|
||||
} else {
|
||||
String title = sa.hasParam("ListTitle") ? sa.getParam("ListTitle") : Localizer.getInstance().getMessage("lblChooseNumber");
|
||||
if (anyNumber) {
|
||||
Integer value = p.getController().announceRequirements(sa, title);
|
||||
chosen = value == null ? 0 : value;
|
||||
} else {
|
||||
chosen = p.getController().chooseNumber(sa, title, min, max);
|
||||
}
|
||||
// don't notify here, because most scripts I've seen don't store that number in a long term
|
||||
}
|
||||
if (secretlyChoose) {
|
||||
chooseMap.put(p, chosen);
|
||||
} else {
|
||||
card.setChosenNumber(chosen);
|
||||
}
|
||||
if (sa.hasParam("Notify")) {
|
||||
p.getGame().getAction().notifyOfValue(sa, card, Localizer.getInstance().getMessage("lblPlayerPickedChosen", p.getName(), chosen), p);
|
||||
chosen = p.getController().chooseNumber(sa, title, min, max);
|
||||
}
|
||||
// don't notify here, because most scripts I've seen don't store that number in a long term
|
||||
}
|
||||
if (secretlyChoose) {
|
||||
chooseMap.put(p, chosen);
|
||||
} else {
|
||||
card.setChosenNumber(chosen);
|
||||
}
|
||||
if (sa.hasParam("Notify")) {
|
||||
p.getGame().getAction().notifyOfValue(sa, card, Localizer.getInstance().getMessage("lblPlayerPickedChosen", p.getName(), chosen), p);
|
||||
}
|
||||
}
|
||||
if (secretlyChoose) {
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
package forge.game.ability.effects;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.SpellAbilityEffect;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.TargetRestrictions;
|
||||
import forge.util.Aggregates;
|
||||
import forge.util.Lang;
|
||||
import forge.util.Localizer;
|
||||
import forge.util.collect.FCollectionView;
|
||||
|
||||
@@ -18,9 +16,8 @@ public class ChoosePlayerEffect extends SpellAbilityEffect {
|
||||
protected String getStackDescription(SpellAbility sa) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
|
||||
for (final Player p : getTargetPlayers(sa)) {
|
||||
sb.append(p).append(" ");
|
||||
}
|
||||
sb.append(Lang.joinHomogenous(getTargetPlayers(sa)));
|
||||
|
||||
sb.append("chooses a player.");
|
||||
|
||||
return sb.toString();
|
||||
@@ -30,56 +27,53 @@ public class ChoosePlayerEffect extends SpellAbilityEffect {
|
||||
public void resolve(SpellAbility sa) {
|
||||
final Card card = sa.getHostCard();
|
||||
|
||||
final List<Player> tgtPlayers = getTargetPlayers(sa);
|
||||
|
||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||
|
||||
final FCollectionView<Player> choices = sa.hasParam("Choices") ? AbilityUtils.getDefinedPlayers(
|
||||
card, sa.getParam("Choices"), sa) : sa.getActivatingPlayer().getGame().getPlayersInTurnOrder();
|
||||
|
||||
final String choiceDesc = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChoosePlayer");
|
||||
final boolean random = sa.hasParam("Random");
|
||||
|
||||
for (final Player p : tgtPlayers) {
|
||||
if ((tgt == null) || p.canBeTargetedBy(sa)) {
|
||||
Player chosen;
|
||||
if (random) {
|
||||
chosen = choices.isEmpty() ? null : Aggregates.random(choices);
|
||||
for (final Player p : getTargetPlayers(sa)) {
|
||||
if (!p.isInGame()) {
|
||||
continue;
|
||||
}
|
||||
Player chosen;
|
||||
if (random) {
|
||||
chosen = choices.isEmpty() ? null : Aggregates.random(choices);
|
||||
} else {
|
||||
chosen = choices.isEmpty() ? null : p.getController().chooseSingleEntityForEffect(choices, sa, choiceDesc, null);
|
||||
}
|
||||
if (null != chosen) {
|
||||
if (sa.hasParam("Secretly")) {
|
||||
card.setSecretChosenPlayer(chosen);
|
||||
} else {
|
||||
chosen = choices.isEmpty() ? null : p.getController().chooseSingleEntityForEffect(choices, sa, choiceDesc, null);
|
||||
card.setChosenPlayer(chosen);
|
||||
}
|
||||
if (sa.hasParam("ForgetOtherRemembered")) {
|
||||
card.clearRemembered();
|
||||
}
|
||||
if (sa.hasParam("RememberChosen")) {
|
||||
card.addRemembered(chosen);
|
||||
}
|
||||
if (null != chosen) {
|
||||
if (sa.hasParam("Secretly")) {
|
||||
card.setSecretChosenPlayer(chosen);
|
||||
} else {
|
||||
card.setChosenPlayer(chosen);
|
||||
}
|
||||
if (sa.hasParam("ForgetOtherRemembered")) {
|
||||
card.clearRemembered();
|
||||
}
|
||||
if (sa.hasParam("RememberChosen")) {
|
||||
card.addRemembered(chosen);
|
||||
}
|
||||
|
||||
// SubAbility that only fires if a player is chosen
|
||||
SpellAbility chosenSA = sa.getAdditionalAbility("ChooseSubAbility");
|
||||
if (chosenSA != null) {
|
||||
if (!chosenSA.getHostCard().equals(sa.getHostCard())) {
|
||||
System.out.println("Warning: ChooseSubAbility had the wrong host set (potentially after cloning the root SA), attempting to correct...");
|
||||
chosenSA.setHostCard(sa.getHostCard());
|
||||
}
|
||||
AbilityUtils.resolve(chosenSA);
|
||||
// SubAbility that only fires if a player is chosen
|
||||
SpellAbility chosenSA = sa.getAdditionalAbility("ChooseSubAbility");
|
||||
if (chosenSA != null) {
|
||||
if (!chosenSA.getHostCard().equals(sa.getHostCard())) {
|
||||
System.out.println("Warning: ChooseSubAbility had the wrong host set (potentially after cloning the root SA), attempting to correct...");
|
||||
chosenSA.setHostCard(sa.getHostCard());
|
||||
}
|
||||
} else {
|
||||
// SubAbility that only fires if a player is not chosen
|
||||
SpellAbility notChosenSA = sa.getAdditionalAbility("CantChooseSubAbility");
|
||||
if (notChosenSA != null) {
|
||||
if (!notChosenSA.getHostCard().equals(sa.getHostCard())) {
|
||||
System.out.println("Warning: CantChooseSubAbility had the wrong host set (potentially after cloning the root SA), attempting to correct...");
|
||||
notChosenSA.setHostCard(sa.getHostCard());
|
||||
}
|
||||
AbilityUtils.resolve(notChosenSA);
|
||||
AbilityUtils.resolve(chosenSA);
|
||||
}
|
||||
} else {
|
||||
// SubAbility that only fires if a player is not chosen
|
||||
SpellAbility notChosenSA = sa.getAdditionalAbility("CantChooseSubAbility");
|
||||
if (notChosenSA != null) {
|
||||
if (!notChosenSA.getHostCard().equals(sa.getHostCard())) {
|
||||
System.out.println("Warning: CantChooseSubAbility had the wrong host set (potentially after cloning the root SA), attempting to correct...");
|
||||
notChosenSA.setHostCard(sa.getHostCard());
|
||||
}
|
||||
AbilityUtils.resolve(notChosenSA);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.SpellAbilityStackInstance;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.util.Lang;
|
||||
import forge.util.Localizer;
|
||||
|
||||
public class ChooseSourceEffect extends SpellAbilityEffect {
|
||||
@@ -22,9 +23,8 @@ public class ChooseSourceEffect extends SpellAbilityEffect {
|
||||
protected String getStackDescription(SpellAbility sa) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
|
||||
for (final Player p : getTargetPlayers(sa)) {
|
||||
sb.append(p).append(" ");
|
||||
}
|
||||
sb.append(Lang.joinHomogenous(getTargetPlayers(sa)));
|
||||
|
||||
sb.append("chooses a source.");
|
||||
|
||||
return sb.toString();
|
||||
@@ -129,21 +129,22 @@ public class ChooseSourceEffect extends SpellAbilityEffect {
|
||||
final int validAmount = StringUtils.isNumeric(numericAmount) ? Integer.parseInt(numericAmount) : AbilityUtils.calculateAmount(host, numericAmount, sa);
|
||||
|
||||
for (final Player p : tgtPlayers) {
|
||||
if (!p.isInGame()) {
|
||||
continue;
|
||||
}
|
||||
final CardCollection chosen = new CardCollection();
|
||||
if (!sa.usesTargeting() || p.canBeTargetedBy(sa)) {
|
||||
for (int i = 0; i < validAmount; i++) {
|
||||
final String choiceTitle = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChooseSource") + " ";
|
||||
Card o = null;
|
||||
do {
|
||||
o = p.getController().chooseSingleEntityForEffect(sourcesToChooseFrom, sa, choiceTitle, null);
|
||||
} while (o == null || o.getName().startsWith("--"));
|
||||
chosen.add(o);
|
||||
sourcesToChooseFrom.remove(o);
|
||||
}
|
||||
host.setChosenCards(chosen);
|
||||
if (sa.hasParam("RememberChosen")) {
|
||||
host.addRemembered(chosen);
|
||||
}
|
||||
for (int i = 0; i < validAmount; i++) {
|
||||
final String choiceTitle = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChooseSource") + " ";
|
||||
Card o = null;
|
||||
do {
|
||||
o = p.getController().chooseSingleEntityForEffect(sourcesToChooseFrom, sa, choiceTitle, null);
|
||||
} while (o == null || o.getName().startsWith("--"));
|
||||
chosen.add(o);
|
||||
sourcesToChooseFrom.remove(o);
|
||||
}
|
||||
host.setChosenCards(chosen);
|
||||
if (sa.hasParam("RememberChosen")) {
|
||||
host.addRemembered(chosen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,9 +13,9 @@ import forge.game.card.CardCollectionView;
|
||||
import forge.game.card.CardFactoryUtil;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.TargetRestrictions;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.util.Aggregates;
|
||||
import forge.util.Lang;
|
||||
|
||||
public class ChooseTypeEffect extends SpellAbilityEffect {
|
||||
|
||||
@@ -24,9 +24,7 @@ public class ChooseTypeEffect extends SpellAbilityEffect {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
|
||||
if (!sa.usesTargeting()) {
|
||||
for (final Player p : getTargetPlayers(sa)) {
|
||||
sb.append(p);
|
||||
}
|
||||
sb.append(Lang.joinHomogenous(getTargetPlayers(sa)));
|
||||
sb.append(" chooses a ").append(sa.getParam("Type").toLowerCase()).append(" type.");
|
||||
} else {
|
||||
sb.append("Please improve the stack description.");
|
||||
@@ -103,30 +101,26 @@ public class ChooseTypeEffect extends SpellAbilityEffect {
|
||||
}
|
||||
}
|
||||
|
||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||
|
||||
if (validTypes.isEmpty() && sa.hasParam("Note")) {
|
||||
// OK to end up with no choices/have nothing new to note
|
||||
} else if (!validTypes.isEmpty()) {
|
||||
for (final Player p : tgtPlayers) {
|
||||
String choice;
|
||||
if ((tgt == null) || p.canBeTargetedBy(sa)) {
|
||||
Player noNotify = p;
|
||||
if (sa.hasParam("AtRandom")) {
|
||||
choice = Aggregates.random(validTypes);
|
||||
noNotify = null;
|
||||
} else {
|
||||
choice = p.getController().chooseSomeType(type, sa, validTypes, invalidTypes);
|
||||
}
|
||||
if (sa.hasParam("Note")) {
|
||||
card.addNotedType(choice);
|
||||
} else if (!sa.hasParam("ChooseType2")) {
|
||||
card.setChosenType(choice);
|
||||
} else {
|
||||
card.setChosenType2(choice);
|
||||
}
|
||||
p.getGame().getAction().notifyOfValue(sa, p, choice, noNotify);
|
||||
Player noNotify = p;
|
||||
if (sa.hasParam("AtRandom")) {
|
||||
choice = Aggregates.random(validTypes);
|
||||
noNotify = null;
|
||||
} else {
|
||||
choice = p.getController().chooseSomeType(type, sa, validTypes, invalidTypes);
|
||||
}
|
||||
if (sa.hasParam("Note")) {
|
||||
card.addNotedType(choice);
|
||||
} else if (!sa.hasParam("ChooseType2")) {
|
||||
card.setChosenType(choice);
|
||||
} else {
|
||||
card.setChosenType2(choice);
|
||||
}
|
||||
p.getGame().getAction().notifyOfValue(sa, p, choice, noNotify);
|
||||
}
|
||||
} else {
|
||||
throw new InvalidParameterException(sa.getHostCard() + "'s ability resulted in no types to choose from");
|
||||
|
||||
@@ -37,7 +37,7 @@ public class ControlPlayerEffect extends SpellAbilityEffect {
|
||||
@Override
|
||||
public void run() {
|
||||
// CR 800.4b
|
||||
if (controller.hasLost()) {
|
||||
if (!controller.isInGame()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -135,6 +135,9 @@ public class CopyPermanentEffect extends TokenEffectBase {
|
||||
}
|
||||
|
||||
for (final Player controller : controllers) {
|
||||
if (!controller.isInGame()) {
|
||||
continue;
|
||||
}
|
||||
List<Card> tgtCards = Lists.newArrayList();
|
||||
|
||||
if (sa.hasParam("ValidSupportedCopy")) {
|
||||
@@ -231,10 +234,8 @@ public class CopyPermanentEffect extends TokenEffectBase {
|
||||
continue;
|
||||
}
|
||||
|
||||
// if it only targets player, it already got all needed cards from defined
|
||||
if (sa.usesTargeting() && !sa.getTargetRestrictions().canTgtPlayer() && !c.canBeTargetedBy(sa)) {
|
||||
continue;
|
||||
}
|
||||
// because copy should be able to copy LKI values, don't handle target and timestamp there
|
||||
|
||||
if (sa.hasParam("ForEach")) {
|
||||
for (Player p : AbilityUtils.getDefinedPlayers(host, sa.getParam("ForEach"), sa)) {
|
||||
Card proto = getProtoType(sa, c, controller);
|
||||
|
||||
@@ -453,124 +453,122 @@ public class CountersPutEffect extends SpellAbilityEffect {
|
||||
}
|
||||
counterAmount = sa.usesTargeting() && sa.isDividedAsYouChoose() ? sa.getDividedValue(gameCard)
|
||||
: counterAmount;
|
||||
if (!sa.usesTargeting() || gameCard.canBeTargetedBy(sa)) {
|
||||
if (max != -1) {
|
||||
counterAmount = Math.max(Math.min(max - gameCard.getCounters(counterType), counterAmount),
|
||||
0);
|
||||
}
|
||||
if (sa.hasParam("UpTo")) {
|
||||
int min = AbilityUtils.calculateAmount(card, sa.getParamOrDefault("UpToMin", "0"), sa);
|
||||
Map<String, Object> params = Maps.newHashMap();
|
||||
params.put("Target", obj);
|
||||
params.put("CounterType", counterType);
|
||||
counterAmount = pc.chooseNumber(sa,
|
||||
Localizer.getInstance().getMessage("lblHowManyCounters"), min, counterAmount, params);
|
||||
}
|
||||
if (sa.isDividedAsYouChoose() && !sa.usesTargeting()) {
|
||||
Map<String, Object> params = Maps.newHashMap();
|
||||
params.put("Target", obj);
|
||||
params.put("CounterType", counterType);
|
||||
divrem++;
|
||||
if (divrem == tgtObjects.size() || counterRemain == 1) {
|
||||
counterAmount = counterRemain;
|
||||
} else {
|
||||
counterAmount = pc.chooseNumber(sa,
|
||||
Localizer.getInstance().getMessage("lblHowManyCountersThis",
|
||||
CardTranslation.getTranslatedName(gameCard.getName())),
|
||||
1, counterRemain, params);
|
||||
}
|
||||
}
|
||||
|
||||
// Adapt need extra logic
|
||||
if (sa.hasParam("Adapt")) {
|
||||
if (!(gameCard.getCounters(CounterEnumType.P1P1) == 0
|
||||
|| StaticAbilityAdapt.anyWithAdapt(sa, gameCard))) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (sa.hasParam("ReadAhead")) {
|
||||
gameCard.setReadAhead(counterAmount);
|
||||
}
|
||||
|
||||
if (sa.hasParam("Tribute")) {
|
||||
// make a copy to check if it would be on the battlefield
|
||||
Card noTributeLKI = CardUtil.getLKICopy(gameCard);
|
||||
// this check needs to check if this card would be on the battlefield
|
||||
noTributeLKI.setLastKnownZone(activator.getZone(ZoneType.Battlefield));
|
||||
|
||||
// double freeze tracker, so it doesn't update view
|
||||
game.getTracker().freeze();
|
||||
|
||||
CardCollection preList = new CardCollection(noTributeLKI);
|
||||
game.getAction().checkStaticAbilities(false, Sets.newHashSet(noTributeLKI), preList);
|
||||
|
||||
boolean abort = !noTributeLKI.canReceiveCounters(counterType);
|
||||
|
||||
game.getAction().checkStaticAbilities(false);
|
||||
// clear delayed changes, this check should not have updated the view
|
||||
game.getTracker().clearDelayed();
|
||||
// need to unfreeze tracker
|
||||
game.getTracker().unfreeze();
|
||||
|
||||
// check if it can receive the Tribute
|
||||
if (abort) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Map<String, Object> params = Maps.newHashMap();
|
||||
params.put("CounterType", counterType);
|
||||
params.put("Amount", counterAmount);
|
||||
params.put("Target", gameCard);
|
||||
|
||||
String message = Localizer.getInstance().getMessage(
|
||||
"lblDoYouWantPutTargetP1P1CountersOnCard", String.valueOf(counterAmount),
|
||||
CardTranslation.getTranslatedName(gameCard.getName()));
|
||||
Player chooser = pc.chooseSingleEntityForEffect(activator.getOpponents(), sa,
|
||||
Localizer.getInstance().getMessage("lblChooseAnOpponent"), params);
|
||||
|
||||
if (chooser.getController().confirmAction(sa, PlayerActionConfirmMode.Tribute, message, null)) {
|
||||
gameCard.setTributed(true);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (etbcounter) {
|
||||
gameCard.addEtbCounter(counterType, counterAmount, placer);
|
||||
if (max != -1) {
|
||||
counterAmount = Math.max(Math.min(max - gameCard.getCounters(counterType), counterAmount),
|
||||
0);
|
||||
}
|
||||
if (sa.hasParam("UpTo")) {
|
||||
int min = AbilityUtils.calculateAmount(card, sa.getParamOrDefault("UpToMin", "0"), sa);
|
||||
Map<String, Object> params = Maps.newHashMap();
|
||||
params.put("Target", obj);
|
||||
params.put("CounterType", counterType);
|
||||
counterAmount = pc.chooseNumber(sa,
|
||||
Localizer.getInstance().getMessage("lblHowManyCounters"), min, counterAmount, params);
|
||||
}
|
||||
if (sa.isDividedAsYouChoose() && !sa.usesTargeting()) {
|
||||
Map<String, Object> params = Maps.newHashMap();
|
||||
params.put("Target", obj);
|
||||
params.put("CounterType", counterType);
|
||||
divrem++;
|
||||
if (divrem == tgtObjects.size() || counterRemain == 1) {
|
||||
counterAmount = counterRemain;
|
||||
} else {
|
||||
gameCard.addCounter(counterType, counterAmount, placer, table);
|
||||
counterAmount = pc.chooseNumber(sa,
|
||||
Localizer.getInstance().getMessage("lblHowManyCountersThis",
|
||||
CardTranslation.getTranslatedName(gameCard.getName())),
|
||||
1, counterRemain, params);
|
||||
}
|
||||
}
|
||||
|
||||
// Adapt need extra logic
|
||||
if (sa.hasParam("Adapt")) {
|
||||
if (!(gameCard.getCounters(CounterEnumType.P1P1) == 0
|
||||
|| StaticAbilityAdapt.anyWithAdapt(sa, gameCard))) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (sa.hasParam("ReadAhead")) {
|
||||
gameCard.setReadAhead(counterAmount);
|
||||
}
|
||||
|
||||
if (sa.hasParam("Tribute")) {
|
||||
// make a copy to check if it would be on the battlefield
|
||||
Card noTributeLKI = CardUtil.getLKICopy(gameCard);
|
||||
// this check needs to check if this card would be on the battlefield
|
||||
noTributeLKI.setLastKnownZone(activator.getZone(ZoneType.Battlefield));
|
||||
|
||||
// double freeze tracker, so it doesn't update view
|
||||
game.getTracker().freeze();
|
||||
|
||||
CardCollection preList = new CardCollection(noTributeLKI);
|
||||
game.getAction().checkStaticAbilities(false, Sets.newHashSet(noTributeLKI), preList);
|
||||
|
||||
boolean abort = !noTributeLKI.canReceiveCounters(counterType);
|
||||
|
||||
game.getAction().checkStaticAbilities(false);
|
||||
// clear delayed changes, this check should not have updated the view
|
||||
game.getTracker().clearDelayed();
|
||||
// need to unfreeze tracker
|
||||
game.getTracker().unfreeze();
|
||||
|
||||
// check if it can receive the Tribute
|
||||
if (abort) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sa.hasParam("Evolve")) {
|
||||
game.getTriggerHandler().runTrigger(TriggerType.Evolved, AbilityKey.mapFromCard(gameCard),
|
||||
false);
|
||||
}
|
||||
if (sa.hasParam("Monstrosity")) {
|
||||
gameCard.setMonstrous(true);
|
||||
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(gameCard);
|
||||
runParams.put(AbilityKey.MonstrosityAmount, counterAmount);
|
||||
game.getTriggerHandler().runTrigger(TriggerType.BecomeMonstrous, runParams, false);
|
||||
}
|
||||
if (sa.hasParam("Renown")) {
|
||||
gameCard.setRenowned(true);
|
||||
game.getTriggerHandler().runTrigger(TriggerType.BecomeRenowned,
|
||||
AbilityKey.mapFromCard(gameCard), false);
|
||||
}
|
||||
if (sa.hasParam("Adapt")) {
|
||||
game.getTriggerHandler().runTrigger(TriggerType.Adapt, AbilityKey.mapFromCard(gameCard),
|
||||
false);
|
||||
}
|
||||
if (sa.hasParam("Training")) {
|
||||
game.getTriggerHandler().runTrigger(TriggerType.Trains, AbilityKey.mapFromCard(gameCard),
|
||||
false);
|
||||
}
|
||||
Map<String, Object> params = Maps.newHashMap();
|
||||
params.put("CounterType", counterType);
|
||||
params.put("Amount", counterAmount);
|
||||
params.put("Target", gameCard);
|
||||
|
||||
game.updateLastStateForCard(gameCard);
|
||||
if (sa.isDividedAsYouChoose() && !sa.usesTargeting()) {
|
||||
counterRemain = counterRemain - counterAmount;
|
||||
String message = Localizer.getInstance().getMessage(
|
||||
"lblDoYouWantPutTargetP1P1CountersOnCard", String.valueOf(counterAmount),
|
||||
CardTranslation.getTranslatedName(gameCard.getName()));
|
||||
Player chooser = pc.chooseSingleEntityForEffect(activator.getOpponents(), sa,
|
||||
Localizer.getInstance().getMessage("lblChooseAnOpponent"), params);
|
||||
|
||||
if (chooser.getController().confirmAction(sa, PlayerActionConfirmMode.Tribute, message, null)) {
|
||||
gameCard.setTributed(true);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (etbcounter) {
|
||||
gameCard.addEtbCounter(counterType, counterAmount, placer);
|
||||
} else {
|
||||
gameCard.addCounter(counterType, counterAmount, placer, table);
|
||||
}
|
||||
|
||||
if (sa.hasParam("Evolve")) {
|
||||
game.getTriggerHandler().runTrigger(TriggerType.Evolved, AbilityKey.mapFromCard(gameCard),
|
||||
false);
|
||||
}
|
||||
if (sa.hasParam("Monstrosity")) {
|
||||
gameCard.setMonstrous(true);
|
||||
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(gameCard);
|
||||
runParams.put(AbilityKey.MonstrosityAmount, counterAmount);
|
||||
game.getTriggerHandler().runTrigger(TriggerType.BecomeMonstrous, runParams, false);
|
||||
}
|
||||
if (sa.hasParam("Renown")) {
|
||||
gameCard.setRenowned(true);
|
||||
game.getTriggerHandler().runTrigger(TriggerType.BecomeRenowned,
|
||||
AbilityKey.mapFromCard(gameCard), false);
|
||||
}
|
||||
if (sa.hasParam("Adapt")) {
|
||||
game.getTriggerHandler().runTrigger(TriggerType.Adapt, AbilityKey.mapFromCard(gameCard),
|
||||
false);
|
||||
}
|
||||
if (sa.hasParam("Training")) {
|
||||
game.getTriggerHandler().runTrigger(TriggerType.Trains, AbilityKey.mapFromCard(gameCard),
|
||||
false);
|
||||
}
|
||||
|
||||
game.updateLastStateForCard(gameCard);
|
||||
if (sa.isDividedAsYouChoose() && !sa.usesTargeting()) {
|
||||
counterRemain = counterRemain - counterAmount;
|
||||
}
|
||||
} else if (obj instanceof Player) {
|
||||
// Add Counters to players!
|
||||
Player pl = (Player) obj;
|
||||
|
||||
@@ -79,18 +79,16 @@ public class CountersPutOrRemoveEffect extends SpellAbilityEffect {
|
||||
CardTranslation.getTranslatedName(gameCard.getName())), null)) {
|
||||
continue;
|
||||
}
|
||||
if (!sa.usesTargeting() || gameCard.canBeTargetedBy(sa)) {
|
||||
if (gameCard.hasCounters()) {
|
||||
if (eachExisting) {
|
||||
for (CounterType listType : Lists.newArrayList(gameCard.getCounters().keySet())) {
|
||||
addOrRemoveCounter(sa, gameCard, listType, counterAmount, table, pl);
|
||||
}
|
||||
} else {
|
||||
addOrRemoveCounter(sa, gameCard, ctype, counterAmount, table, pl);
|
||||
if (gameCard.hasCounters()) {
|
||||
if (eachExisting) {
|
||||
for (CounterType listType : Lists.newArrayList(gameCard.getCounters().keySet())) {
|
||||
addOrRemoveCounter(sa, gameCard, listType, counterAmount, table, pl);
|
||||
}
|
||||
} else if (!eachExisting && ctype != null) {
|
||||
gameCard.addCounter(ctype, counterAmount, pl, table);
|
||||
} else {
|
||||
addOrRemoveCounter(sa, gameCard, ctype, counterAmount, table, pl);
|
||||
}
|
||||
} else if (!eachExisting && ctype != null) {
|
||||
gameCard.addCounter(ctype, counterAmount, pl, table);
|
||||
}
|
||||
}
|
||||
table.replaceCounterEffect(game, sa, true);
|
||||
|
||||
@@ -103,21 +103,22 @@ public class CountersRemoveEffect extends SpellAbilityEffect {
|
||||
boolean rememberAmount = sa.hasParam("RememberAmount");
|
||||
|
||||
for (final Player tgtPlayer : getTargetPlayers(sa)) {
|
||||
if (!tgtPlayer.isInGame()) {
|
||||
continue;
|
||||
}
|
||||
// Removing energy
|
||||
if (!sa.usesTargeting() || tgtPlayer.canBeTargetedBy(sa)) {
|
||||
if (type.equals("All")) {
|
||||
for (Map.Entry<CounterType, Integer> e : Lists.newArrayList(tgtPlayer.getCounters().entrySet())) {
|
||||
tgtPlayer.subtractCounter(e.getKey(), e.getValue());
|
||||
}
|
||||
if (type.equals("All")) {
|
||||
for (Map.Entry<CounterType, Integer> e : Lists.newArrayList(tgtPlayer.getCounters().entrySet())) {
|
||||
tgtPlayer.subtractCounter(e.getKey(), e.getValue());
|
||||
}
|
||||
} else {
|
||||
if (num.equals("All")) {
|
||||
cntToRemove = tgtPlayer.getCounters(counterType);
|
||||
}
|
||||
if (type.equals("Any")) {
|
||||
removeAnyType(tgtPlayer, cntToRemove, sa);
|
||||
} else {
|
||||
if (num.equals("All")) {
|
||||
cntToRemove = tgtPlayer.getCounters(counterType);
|
||||
}
|
||||
if (type.equals("Any")) {
|
||||
removeAnyType(tgtPlayer, cntToRemove, sa);
|
||||
} else {
|
||||
tgtPlayer.subtractCounter(counterType, cntToRemove);
|
||||
}
|
||||
tgtPlayer.subtractCounter(counterType, cntToRemove);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -160,44 +161,42 @@ public class CountersRemoveEffect extends SpellAbilityEffect {
|
||||
if (gameCard == null || !tgtCard.equalsWithTimestamp(gameCard)) {
|
||||
continue;
|
||||
}
|
||||
if (!sa.usesTargeting() || gameCard.canBeTargetedBy(sa)) {
|
||||
final Zone zone = game.getZoneOf(gameCard);
|
||||
if (type.equals("All")) {
|
||||
for (Map.Entry<CounterType, Integer> e : Lists.newArrayList(gameCard.getCounters().entrySet())) {
|
||||
gameCard.subtractCounter(e.getKey(), e.getValue());
|
||||
final Zone zone = game.getZoneOf(gameCard);
|
||||
if (type.equals("All")) {
|
||||
for (Map.Entry<CounterType, Integer> e : Lists.newArrayList(gameCard.getCounters().entrySet())) {
|
||||
gameCard.subtractCounter(e.getKey(), e.getValue());
|
||||
}
|
||||
game.updateLastStateForCard(gameCard);
|
||||
continue;
|
||||
} else if (num.equals("All") || num.equals("Any")) {
|
||||
cntToRemove = gameCard.getCounters(counterType);
|
||||
}
|
||||
|
||||
if (type.equals("Any")) {
|
||||
removeAnyType(gameCard, cntToRemove, sa);
|
||||
} else {
|
||||
cntToRemove = Math.min(cntToRemove, gameCard.getCounters(counterType));
|
||||
|
||||
if (zone.is(ZoneType.Battlefield) || zone.is(ZoneType.Exile)) {
|
||||
if (sa.hasParam("UpTo") || num.equals("Any")) {
|
||||
Map<String, Object> params = Maps.newHashMap();
|
||||
params.put("Target", gameCard);
|
||||
params.put("CounterType", counterType);
|
||||
title = Localizer.getInstance().getMessage("lblSelectRemoveCountersNumberOfTarget", type);
|
||||
cntToRemove = pc.chooseNumber(sa, title, 0, cntToRemove, params);
|
||||
}
|
||||
}
|
||||
if (cntToRemove > 0) {
|
||||
gameCard.subtractCounter(counterType, cntToRemove);
|
||||
if (rememberRemoved) {
|
||||
for (int i = 0; i < cntToRemove; i++) {
|
||||
// TODO might need to be more specific
|
||||
card.addRemembered(Pair.of(counterType, i));
|
||||
}
|
||||
}
|
||||
game.updateLastStateForCard(gameCard);
|
||||
continue;
|
||||
} else if (num.equals("All") || num.equals("Any")) {
|
||||
cntToRemove = gameCard.getCounters(counterType);
|
||||
}
|
||||
|
||||
if (type.equals("Any")) {
|
||||
removeAnyType(gameCard, cntToRemove, sa);
|
||||
} else {
|
||||
cntToRemove = Math.min(cntToRemove, gameCard.getCounters(counterType));
|
||||
|
||||
if (zone.is(ZoneType.Battlefield) || zone.is(ZoneType.Exile)) {
|
||||
if (sa.hasParam("UpTo") || num.equals("Any")) {
|
||||
Map<String, Object> params = Maps.newHashMap();
|
||||
params.put("Target", gameCard);
|
||||
params.put("CounterType", counterType);
|
||||
title = Localizer.getInstance().getMessage("lblSelectRemoveCountersNumberOfTarget", type);
|
||||
cntToRemove = pc.chooseNumber(sa, title, 0, cntToRemove, params);
|
||||
}
|
||||
}
|
||||
if (cntToRemove > 0) {
|
||||
gameCard.subtractCounter(counterType, cntToRemove);
|
||||
if (rememberRemoved) {
|
||||
for (int i = 0; i < cntToRemove; i++) {
|
||||
// TODO might need to be more specific
|
||||
card.addRemembered(Pair.of(counterType, i));
|
||||
}
|
||||
}
|
||||
game.updateLastStateForCard(gameCard);
|
||||
|
||||
totalRemoved += cntToRemove;
|
||||
}
|
||||
totalRemoved += cntToRemove;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -272,14 +272,10 @@ public class DamageDealEffect extends DamageBaseEffect {
|
||||
if (c.isPhasedOut()) {
|
||||
continue;
|
||||
}
|
||||
if (!sa.usesTargeting() || gc.canBeTargetedBy(sa)) {
|
||||
internalDamageDeal(sa, sourceLKI, gc, dmg, damageMap);
|
||||
}
|
||||
internalDamageDeal(sa, sourceLKI, gc, dmg, damageMap);
|
||||
} else if (o instanceof Player) {
|
||||
final Player p = (Player) o;
|
||||
if (!sa.usesTargeting() || p.canBeTargetedBy(sa)) {
|
||||
damageMap.put(sourceLKI, p, dmg);
|
||||
}
|
||||
damageMap.put(sourceLKI, p, dmg);
|
||||
}
|
||||
}
|
||||
for (final Card unTgtC : untargetedCards) {
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
package forge.game.ability.effects;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import forge.game.Game;
|
||||
import forge.game.GameEntityCounterTable;
|
||||
import forge.game.GameObject;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardDamageMap;
|
||||
@@ -68,10 +65,6 @@ public class DamageEachEffect extends DamageBaseEffect {
|
||||
sources = CardLists.getValidCards(sources, sa.getParam("ValidCards"), sa.getActivatingPlayer(), card, sa);
|
||||
}
|
||||
|
||||
final List<GameObject> tgts = getTargets(sa, "DefinedPlayers");
|
||||
|
||||
final boolean targeted = sa.usesTargeting();
|
||||
|
||||
boolean usedDamageMap = true;
|
||||
CardDamageMap damageMap = sa.getDamageMap();
|
||||
CardDamageMap preventMap = sa.getPreventMap();
|
||||
@@ -85,7 +78,7 @@ public class DamageEachEffect extends DamageBaseEffect {
|
||||
usedDamageMap = false;
|
||||
}
|
||||
|
||||
for (final Object o : tgts) {
|
||||
for (final Object o : getTargetEntities(sa, "DefinedPlayers")) {
|
||||
for (final Card source : sources) {
|
||||
final Card sourceLKI = game.getChangeZoneLKIInfo(source);
|
||||
|
||||
@@ -94,15 +87,12 @@ public class DamageEachEffect extends DamageBaseEffect {
|
||||
|
||||
if (o instanceof Card) {
|
||||
final Card c = (Card) o;
|
||||
if (c.isInPlay() && (!targeted || c.canBeTargetedBy(sa))) {
|
||||
if (c.isInPlay()) {
|
||||
damageMap.put(sourceLKI, c, dmg);
|
||||
}
|
||||
|
||||
} else if (o instanceof Player) {
|
||||
final Player p = (Player) o;
|
||||
if (!targeted || p.canBeTargetedBy(sa)) {
|
||||
damageMap.put(sourceLKI, p, dmg);
|
||||
}
|
||||
damageMap.put(sourceLKI, (Player) o, dmg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,20 +93,15 @@ public class DamagePreventEffect extends DamagePreventEffectBase {
|
||||
|
||||
final CardCollection untargetedCards = CardUtil.getRadiance(sa);
|
||||
|
||||
final boolean targeted = sa.usesTargeting();
|
||||
|
||||
for (final GameObject o : tgts) {
|
||||
numDam = targeted && sa.isDividedAsYouChoose() ? sa.getDividedValue(o) : numDam;
|
||||
numDam = sa.usesTargeting() && sa.isDividedAsYouChoose() ? sa.getDividedValue(o) : numDam;
|
||||
if (o instanceof Card) {
|
||||
final Card c = (Card) o;
|
||||
if (c.isInPlay() && (!targeted || c.canBeTargetedBy(sa))) {
|
||||
if (c.isInPlay()) {
|
||||
addPreventNextDamage(sa, o, numDam);
|
||||
}
|
||||
} else if (o instanceof Player) {
|
||||
final Player p = (Player) o;
|
||||
if (!targeted || p.canBeTargetedBy(sa)) {
|
||||
addPreventNextDamage(sa, o, numDam);
|
||||
}
|
||||
addPreventNextDamage(sa, o, numDam);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,5 +110,5 @@ public class DamagePreventEffect extends DamagePreventEffectBase {
|
||||
addPreventNextDamage(sa, c, numDam);
|
||||
}
|
||||
}
|
||||
} // preventDamageResolve
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,80 +69,92 @@ public class DebuffEffect extends SpellAbilityEffect {
|
||||
final long timestamp = game.getNextTimestamp();
|
||||
|
||||
for (final Card tgtC : getTargetCards(sa)) {
|
||||
if (!tgtC.isInPlay()) {
|
||||
continue;
|
||||
}
|
||||
if (tgtC.isPhasedOut()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// check if the object is still in game or if it was moved
|
||||
Card gameCard = game.getCardState(tgtC, null);
|
||||
// gameCard is LKI in that case, the card is not in game anymore
|
||||
// or the timestamp did change
|
||||
// this should check Self too
|
||||
if (gameCard == null || !tgtC.equalsWithTimestamp(gameCard)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final List<String> addedKW = Lists.newArrayList();
|
||||
final List<String> removedKW = Lists.newArrayList();
|
||||
if (tgtC.isInPlay() && (!sa.usesTargeting() || tgtC.canBeTargetedBy(sa))) {
|
||||
if (sa.hasParam("AllSuffixKeywords")) {
|
||||
// this only for walk abilities, may to try better
|
||||
if (sa.getParam("AllSuffixKeywords").equals("walk")) {
|
||||
for (final KeywordInterface kw : tgtC.getKeywords(Keyword.LANDWALK)) {
|
||||
removedKW.add(kw.getOriginal());
|
||||
}
|
||||
|
||||
if (sa.hasParam("AllSuffixKeywords")) {
|
||||
// this only for walk abilities, may to try better
|
||||
if (sa.getParam("AllSuffixKeywords").equals("walk")) {
|
||||
for (final KeywordInterface kw : tgtC.getKeywords(Keyword.LANDWALK)) {
|
||||
removedKW.add(kw.getOriginal());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// special for Protection:Card.<color>:Protection from <color>:*
|
||||
for (final KeywordInterface inst : tgtC.getUnhiddenKeywords()) {
|
||||
String keyword = inst.getOriginal();
|
||||
if (keyword.startsWith("Protection:")) {
|
||||
for (final String kw : kws) {
|
||||
if (keyword.matches("(?i).*:" + kw))
|
||||
removedKW.add(keyword);
|
||||
}
|
||||
// special for Protection:Card.<color>:Protection from <color>:*
|
||||
for (final KeywordInterface inst : tgtC.getUnhiddenKeywords()) {
|
||||
String keyword = inst.getOriginal();
|
||||
if (keyword.startsWith("Protection:")) {
|
||||
for (final String kw : kws) {
|
||||
if (keyword.matches("(?i).*:" + kw))
|
||||
removedKW.add(keyword);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean ProtectionFromColor = false;
|
||||
for (final String kw : kws) {
|
||||
// Check if some of the Keywords are Protection from <color>
|
||||
if (!ProtectionFromColor && kw.startsWith("Protection from ")) {
|
||||
for (byte col : MagicColor.WUBRG) {
|
||||
final String colString = MagicColor.toLongString(col);
|
||||
if (kw.endsWith(colString.toLowerCase())) {
|
||||
ProtectionFromColor = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Split "Protection from all colors" into extra Protection from <color>
|
||||
String allColors = "Protection from all colors";
|
||||
if (ProtectionFromColor && tgtC.hasKeyword(allColors)) {
|
||||
final List<String> allColorsProtect = Lists.newArrayList();
|
||||
|
||||
for (byte col : MagicColor.WUBRG) {
|
||||
allColorsProtect.add("Protection from " + MagicColor.toLongString(col).toLowerCase());
|
||||
}
|
||||
allColorsProtect.removeAll(kws);
|
||||
addedKW.addAll(allColorsProtect);
|
||||
removedKW.add(allColors);
|
||||
}
|
||||
|
||||
// Extra for Spectra Ward
|
||||
allColors = "Protection:Card.nonColorless:Protection from all colors:Aura";
|
||||
if (ProtectionFromColor && tgtC.hasKeyword(allColors)) {
|
||||
final List<String> allColorsProtect = Lists.newArrayList();
|
||||
|
||||
boolean ProtectionFromColor = false;
|
||||
for (final String kw : kws) {
|
||||
// Check if some of the Keywords are Protection from <color>
|
||||
if (!ProtectionFromColor && kw.startsWith("Protection from ")) {
|
||||
for (byte col : MagicColor.WUBRG) {
|
||||
final String colString = MagicColor.toLongString(col);
|
||||
if (!kws.contains("Protection from " + colString)) {
|
||||
allColorsProtect.add(
|
||||
"Protection:Card." + StringUtils.capitalize(colString) +
|
||||
":Protection from " + colString + ":Aura"
|
||||
);
|
||||
if (kw.endsWith(colString.toLowerCase())) {
|
||||
ProtectionFromColor = true;
|
||||
}
|
||||
}
|
||||
addedKW.addAll(allColorsProtect);
|
||||
removedKW.add(allColors);
|
||||
}
|
||||
|
||||
removedKW.addAll(kws);
|
||||
tgtC.addChangedCardKeywords(addedKW, removedKW, false, timestamp, 0);
|
||||
}
|
||||
|
||||
// Split "Protection from all colors" into extra Protection from <color>
|
||||
String allColors = "Protection from all colors";
|
||||
if (ProtectionFromColor && tgtC.hasKeyword(allColors)) {
|
||||
final List<String> allColorsProtect = Lists.newArrayList();
|
||||
|
||||
for (byte col : MagicColor.WUBRG) {
|
||||
allColorsProtect.add("Protection from " + MagicColor.toLongString(col).toLowerCase());
|
||||
}
|
||||
allColorsProtect.removeAll(kws);
|
||||
addedKW.addAll(allColorsProtect);
|
||||
removedKW.add(allColors);
|
||||
}
|
||||
|
||||
// Extra for Spectra Ward
|
||||
allColors = "Protection:Card.nonColorless:Protection from all colors:Aura";
|
||||
if (ProtectionFromColor && tgtC.hasKeyword(allColors)) {
|
||||
final List<String> allColorsProtect = Lists.newArrayList();
|
||||
|
||||
for (byte col : MagicColor.WUBRG) {
|
||||
final String colString = MagicColor.toLongString(col);
|
||||
if (!kws.contains("Protection from " + colString)) {
|
||||
allColorsProtect.add(
|
||||
"Protection:Card." + StringUtils.capitalize(colString) +
|
||||
":Protection from " + colString + ":Aura"
|
||||
);
|
||||
}
|
||||
}
|
||||
addedKW.addAll(allColorsProtect);
|
||||
removedKW.add(allColors);
|
||||
}
|
||||
|
||||
removedKW.addAll(kws);
|
||||
tgtC.addChangedCardKeywords(addedKW, removedKW, false, timestamp, 0);
|
||||
|
||||
if (!"Permanent".equals(sa.getParam("Duration"))) {
|
||||
final GameCommand until = new GameCommand() {
|
||||
private static final long serialVersionUID = 5387486776282932314L;
|
||||
@@ -155,6 +167,6 @@ public class DebuffEffect extends SpellAbilityEffect {
|
||||
addUntilCommand(sa, until);
|
||||
}
|
||||
}
|
||||
} // debuffResolve
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -64,16 +64,17 @@ public class DestroyEffect extends SpellAbilityEffect {
|
||||
CardZoneTable table = new CardZoneTable();
|
||||
Map<Integer, Card> cachedMap = Maps.newHashMap();
|
||||
for (final Card tgtC : tgtCards) {
|
||||
if (tgtC.isInPlay() && (!sa.usesTargeting() || tgtC.canBeTargetedBy(sa))) {
|
||||
Card gameCard = game.getCardState(tgtC, null);
|
||||
// gameCard is LKI in that case, the card is not in game anymore
|
||||
// or the timestamp did change
|
||||
// this should check Self too
|
||||
if (gameCard == null || !tgtC.equalsWithTimestamp(gameCard)) {
|
||||
continue;
|
||||
}
|
||||
internalDestroy(gameCard, sa, table, cachedMap, params);
|
||||
if (!tgtC.isInPlay()) {
|
||||
continue;
|
||||
}
|
||||
Card gameCard = game.getCardState(tgtC, null);
|
||||
// gameCard is LKI in that case, the card is not in game anymore
|
||||
// or the timestamp did change
|
||||
// this should check Self too
|
||||
if (gameCard == null || !tgtC.equalsWithTimestamp(gameCard)) {
|
||||
continue;
|
||||
}
|
||||
internalDestroy(gameCard, sa, table, cachedMap, params);
|
||||
}
|
||||
|
||||
if (untargetedCards.size() > 1) {
|
||||
|
||||
@@ -15,7 +15,6 @@ import forge.game.player.DelayedReveal;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.TargetRestrictions;
|
||||
import forge.game.zone.PlayerZone;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.util.CardTranslation;
|
||||
@@ -169,19 +168,17 @@ public class DigEffect extends SpellAbilityEffect {
|
||||
}
|
||||
}
|
||||
|
||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||
final List<Player> tgtPlayers = getDefinedPlayersOrTargeted(sa);
|
||||
|
||||
CardZoneTable table = new CardZoneTable();
|
||||
GameEntityCounterTable counterTable = new GameEntityCounterTable();
|
||||
boolean combatChanged = false;
|
||||
CardCollectionView lastStateBattlefield = game.copyLastStateBattlefield();
|
||||
CardCollectionView lastStateGraveyard = game.copyLastStateGraveyard();
|
||||
|
||||
for (final Player p : tgtPlayers) {
|
||||
if (tgt != null && !p.canBeTargetedBy(sa)) {
|
||||
for (final Player p : getDefinedPlayersOrTargeted(sa)) {
|
||||
if (!p.isInGame()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final CardCollection top = new CardCollection();
|
||||
final CardCollection rest = new CardCollection();
|
||||
CardCollection all = new CardCollection(p.getCardsIn(srcZone));
|
||||
|
||||
@@ -40,7 +40,7 @@ public class DigMultipleEffect extends SpellAbilityEffect {
|
||||
|
||||
CardZoneTable table = new CardZoneTable();
|
||||
for (final Player chooser : getDefinedPlayersOrTargeted(sa)) {
|
||||
if (sa.usesTargeting() && !chooser.canBeTargetedBy(sa)) {
|
||||
if (!chooser.isInGame()) {
|
||||
continue;
|
||||
}
|
||||
final CardCollection top = new CardCollection();
|
||||
|
||||
@@ -122,146 +122,144 @@ public class DigUntilEffect extends SpellAbilityEffect {
|
||||
CardCollectionView lastStateGraveyard = game.copyLastStateGraveyard();
|
||||
|
||||
for (final Player p : getTargetPlayers(sa)) {
|
||||
if (p == null) {
|
||||
if (p == null || !p.isInGame()) {
|
||||
continue;
|
||||
}
|
||||
if (!sa.usesTargeting() || p.canBeTargetedBy(sa)) {
|
||||
if (optional && !p.getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblDoYouWantDigYourLibrary"), null)) {
|
||||
continue;
|
||||
if (optional && !p.getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblDoYouWantDigYourLibrary"), null)) {
|
||||
continue;
|
||||
}
|
||||
CardCollection found = new CardCollection();
|
||||
CardCollection revealed = new CardCollection();
|
||||
|
||||
final PlayerZone library = p.getZone(digSite);
|
||||
|
||||
final int maxToDig = maxRevealed != null ? maxRevealed : library.size();
|
||||
|
||||
for (int i = 0; i < maxToDig; i++) {
|
||||
final Card c = library.get(i);
|
||||
revealed.add(c);
|
||||
if (c.isValid(type, sa.getActivatingPlayer(), host, sa)) {
|
||||
found.add(c);
|
||||
if (sa.hasParam("ForgetOtherRemembered")) {
|
||||
host.clearRemembered();
|
||||
}
|
||||
if (remember) {
|
||||
host.addRemembered(c);
|
||||
}
|
||||
if (imprint) {
|
||||
host.addImprintedCard(c);
|
||||
}
|
||||
if (found.size() == untilAmount) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
CardCollection found = new CardCollection();
|
||||
CardCollection revealed = new CardCollection();
|
||||
}
|
||||
|
||||
final PlayerZone library = p.getZone(digSite);
|
||||
if (shuffle && sa.hasParam("ShuffleCondition")) {
|
||||
if (sa.getParam("ShuffleCondition").equals("NoneFound")) {
|
||||
shuffle = found.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
final int maxToDig = maxRevealed != null ? maxRevealed : library.size();
|
||||
if (revealed.size() > 0) {
|
||||
game.getAction().reveal(revealed, p, false);
|
||||
}
|
||||
|
||||
for (int i = 0; i < maxToDig; i++) {
|
||||
final Card c = library.get(i);
|
||||
revealed.add(c);
|
||||
if (c.isValid(type, sa.getActivatingPlayer(), host, sa)) {
|
||||
found.add(c);
|
||||
if (sa.hasParam("ForgetOtherRemembered")) {
|
||||
host.clearRemembered();
|
||||
if (foundDest != null) {
|
||||
// Allow ordering of found cards
|
||||
if (foundDest.isKnown() && found.size() >= 2 && !foundDest.equals(ZoneType.Exile)) {
|
||||
found = (CardCollection)p.getController().orderMoveToZoneList(found, foundDest, sa);
|
||||
}
|
||||
|
||||
final Iterator<Card> itr = found.iterator();
|
||||
while (itr.hasNext()) {
|
||||
final Card c = itr.next();
|
||||
final ZoneType origin = c.getZone().getZoneType();
|
||||
if (optionalFound && !p.getController().confirmAction(sa, null,
|
||||
Localizer.getInstance().getMessage("lblDoYouWantPutCardToZone", foundDest.getTranslatedName()), null)) {
|
||||
continue;
|
||||
}
|
||||
Map<AbilityKey, Object> moveParams = AbilityKey.newMap();
|
||||
moveParams.put(AbilityKey.LastStateBattlefield, lastStateBattlefield);
|
||||
moveParams.put(AbilityKey.LastStateGraveyard, lastStateGraveyard);
|
||||
Card m = null;
|
||||
if (sa.hasParam("GainControl") && foundDest.equals(ZoneType.Battlefield)) {
|
||||
c.setController(sa.getActivatingPlayer(), game.getNextTimestamp());
|
||||
if (sa.hasParam("Tapped")) {
|
||||
c.setTapped(true);
|
||||
}
|
||||
if (remember) {
|
||||
host.addRemembered(c);
|
||||
}
|
||||
if (imprint) {
|
||||
host.addImprintedCard(c);
|
||||
}
|
||||
if (found.size() == untilAmount) {
|
||||
break;
|
||||
m = game.getAction().moveTo(c.getController().getZone(foundDest), c, sa, moveParams);
|
||||
if (addToCombat(c, c.getController(), sa, "Attacking", "Blocking")) {
|
||||
combatChanged = true;
|
||||
}
|
||||
} else if (sa.hasParam("NoMoveFound") && foundDest.equals(ZoneType.Library)) {
|
||||
//Don't do anything
|
||||
} else {
|
||||
m = game.getAction().moveTo(foundDest, c, foundLibPos, sa, moveParams);
|
||||
}
|
||||
revealed.remove(c);
|
||||
if (m != null && !origin.equals(m.getZone().getZoneType())) {
|
||||
table.put(origin, m.getZone().getZoneType(), m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shuffle && sa.hasParam("ShuffleCondition")) {
|
||||
if (sa.getParam("ShuffleCondition").equals("NoneFound")) {
|
||||
shuffle = found.isEmpty();
|
||||
}
|
||||
if (sa.hasParam("RememberRevealed")) {
|
||||
host.addRemembered(revealed);
|
||||
}
|
||||
if (sa.hasParam("ImprintRevealed")) {
|
||||
host.addImprintedCards(revealed);
|
||||
}
|
||||
if (sa.hasParam("RevealRandomOrder")) {
|
||||
Collections.shuffle(revealed, MyRandom.getRandom());
|
||||
}
|
||||
|
||||
if (sa.hasParam("NoMoveRevealed")) {
|
||||
//don't do anything
|
||||
} else if (sa.hasParam("NoneFoundDestination") && found.size() < untilAmount) {
|
||||
// Allow ordering the revealed cards
|
||||
if (noneFoundDest.isKnown() && revealed.size() >= 2) {
|
||||
revealed = (CardCollection)p.getController().orderMoveToZoneList(revealed, noneFoundDest, sa);
|
||||
}
|
||||
if (noneFoundDest == ZoneType.Library && !shuffle
|
||||
&& !sa.hasParam("RevealRandomOrder") && revealed.size() >= 2) {
|
||||
revealed = (CardCollection)p.getController().orderMoveToZoneList(revealed, noneFoundDest, sa);
|
||||
}
|
||||
|
||||
if (revealed.size() > 0) {
|
||||
game.getAction().reveal(revealed, p, false);
|
||||
}
|
||||
|
||||
if (foundDest != null) {
|
||||
// Allow ordering of found cards
|
||||
if (foundDest.isKnown() && found.size() >= 2 && !foundDest.equals(ZoneType.Exile)) {
|
||||
found = (CardCollection)p.getController().orderMoveToZoneList(found, foundDest, sa);
|
||||
}
|
||||
|
||||
final Iterator<Card> itr = found.iterator();
|
||||
while (itr.hasNext()) {
|
||||
final Card c = itr.next();
|
||||
final ZoneType origin = c.getZone().getZoneType();
|
||||
if (optionalFound && !p.getController().confirmAction(sa, null,
|
||||
Localizer.getInstance().getMessage("lblDoYouWantPutCardToZone", foundDest.getTranslatedName()), null)) {
|
||||
continue;
|
||||
}
|
||||
Map<AbilityKey, Object> moveParams = AbilityKey.newMap();
|
||||
moveParams.put(AbilityKey.LastStateBattlefield, lastStateBattlefield);
|
||||
moveParams.put(AbilityKey.LastStateGraveyard, lastStateGraveyard);
|
||||
Card m = null;
|
||||
if (sa.hasParam("GainControl") && foundDest.equals(ZoneType.Battlefield)) {
|
||||
c.setController(sa.getActivatingPlayer(), game.getNextTimestamp());
|
||||
if (sa.hasParam("Tapped")) {
|
||||
c.setTapped(true);
|
||||
}
|
||||
m = game.getAction().moveTo(c.getController().getZone(foundDest), c, sa, moveParams);
|
||||
if (addToCombat(c, c.getController(), sa, "Attacking", "Blocking")) {
|
||||
combatChanged = true;
|
||||
}
|
||||
} else if (sa.hasParam("NoMoveFound") && foundDest.equals(ZoneType.Library)) {
|
||||
//Don't do anything
|
||||
} else {
|
||||
m = game.getAction().moveTo(foundDest, c, foundLibPos, sa, moveParams);
|
||||
}
|
||||
revealed.remove(c);
|
||||
if (m != null && !origin.equals(m.getZone().getZoneType())) {
|
||||
table.put(origin, m.getZone().getZoneType(), m);
|
||||
}
|
||||
final Iterator<Card> itr = revealed.iterator();
|
||||
while (itr.hasNext()) {
|
||||
final Card c = itr.next();
|
||||
final ZoneType origin = c.getZone().getZoneType();
|
||||
final Card m = game.getAction().moveTo(noneFoundDest, c, noneFoundLibPos, sa);
|
||||
if (m != null && !origin.equals(m.getZone().getZoneType())) {
|
||||
table.put(origin, m.getZone().getZoneType(), m);
|
||||
}
|
||||
}
|
||||
|
||||
if (sa.hasParam("RememberRevealed")) {
|
||||
host.addRemembered(revealed);
|
||||
} else {
|
||||
// Allow ordering the rest of the revealed cards
|
||||
if (revealedDest.isKnown() && revealed.size() >= 2 && !sa.hasParam("SkipReorder")) {
|
||||
revealed = (CardCollection)p.getController().orderMoveToZoneList(revealed, revealedDest, sa);
|
||||
}
|
||||
if (sa.hasParam("ImprintRevealed")) {
|
||||
host.addImprintedCards(revealed);
|
||||
}
|
||||
if (sa.hasParam("RevealRandomOrder")) {
|
||||
Collections.shuffle(revealed, MyRandom.getRandom());
|
||||
if (revealedDest == ZoneType.Library && !shuffle
|
||||
&& !sa.hasParam("RevealRandomOrder") && revealed.size() >= 2) {
|
||||
revealed = (CardCollection)p.getController().orderMoveToZoneList(revealed, revealedDest, sa);
|
||||
}
|
||||
|
||||
if (sa.hasParam("NoMoveRevealed")) {
|
||||
//don't do anything
|
||||
} else if (sa.hasParam("NoneFoundDestination") && found.size() < untilAmount) {
|
||||
// Allow ordering the revealed cards
|
||||
if (noneFoundDest.isKnown() && revealed.size() >= 2) {
|
||||
revealed = (CardCollection)p.getController().orderMoveToZoneList(revealed, noneFoundDest, sa);
|
||||
}
|
||||
if (noneFoundDest == ZoneType.Library && !shuffle
|
||||
&& !sa.hasParam("RevealRandomOrder") && revealed.size() >= 2) {
|
||||
revealed = (CardCollection)p.getController().orderMoveToZoneList(revealed, noneFoundDest, sa);
|
||||
}
|
||||
|
||||
final Iterator<Card> itr = revealed.iterator();
|
||||
while (itr.hasNext()) {
|
||||
final Card c = itr.next();
|
||||
final ZoneType origin = c.getZone().getZoneType();
|
||||
final Card m = game.getAction().moveTo(noneFoundDest, c, noneFoundLibPos, sa);
|
||||
if (m != null && !origin.equals(m.getZone().getZoneType())) {
|
||||
table.put(origin, m.getZone().getZoneType(), m);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Allow ordering the rest of the revealed cards
|
||||
if (revealedDest.isKnown() && revealed.size() >= 2 && !sa.hasParam("SkipReorder")) {
|
||||
revealed = (CardCollection)p.getController().orderMoveToZoneList(revealed, revealedDest, sa);
|
||||
}
|
||||
if (revealedDest == ZoneType.Library && !shuffle
|
||||
&& !sa.hasParam("RevealRandomOrder") && revealed.size() >= 2) {
|
||||
revealed = (CardCollection)p.getController().orderMoveToZoneList(revealed, revealedDest, sa);
|
||||
}
|
||||
|
||||
final Iterator<Card> itr = revealed.iterator();
|
||||
while (itr.hasNext()) {
|
||||
final Card c = itr.next();
|
||||
final ZoneType origin = c.getZone().getZoneType();
|
||||
final Card m = game.getAction().moveTo(revealedDest, c, revealedLibPos, sa);
|
||||
if (m != null && !origin.equals(m.getZone().getZoneType())) {
|
||||
table.put(origin, m.getZone().getZoneType(), m);
|
||||
}
|
||||
final Iterator<Card> itr = revealed.iterator();
|
||||
while (itr.hasNext()) {
|
||||
final Card c = itr.next();
|
||||
final ZoneType origin = c.getZone().getZoneType();
|
||||
final Card m = game.getAction().moveTo(revealedDest, c, revealedLibPos, sa);
|
||||
if (m != null && !origin.equals(m.getZone().getZoneType())) {
|
||||
table.put(origin, m.getZone().getZoneType(), m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shuffle) {
|
||||
p.shuffle(sa);
|
||||
}
|
||||
} // end foreach player
|
||||
}
|
||||
if (shuffle) {
|
||||
p.shuffle(sa);
|
||||
}
|
||||
} // end foreach player
|
||||
if (combatChanged) {
|
||||
game.updateCombatForView();
|
||||
game.fireEvent(new GameEventCombatChanged());
|
||||
|
||||
@@ -134,9 +134,6 @@ public class DiscardEffect extends SpellAbilityEffect {
|
||||
// In this case the target need not be the discarding player
|
||||
discarders = getDefinedPlayersOrTargeted(sa);
|
||||
firstTarget = Iterables.getFirst(targets, null);
|
||||
if (sa.usesTargeting() && !firstTarget.canBeTargetedBy(sa)) {
|
||||
firstTarget = null;
|
||||
}
|
||||
} else {
|
||||
discarders = targets;
|
||||
}
|
||||
@@ -144,6 +141,10 @@ public class DiscardEffect extends SpellAbilityEffect {
|
||||
final CardZoneTable table = new CardZoneTable();
|
||||
Map<Player, CardCollectionView> discardedMap = Maps.newHashMap();
|
||||
for (final Player p : discarders) {
|
||||
if (!p.isInGame()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
CardCollectionView toBeDiscarded = new CardCollection();
|
||||
if ((mode.equals("RevealTgtChoose") && firstTarget != null) || !sa.usesTargeting() || p.canBeTargetedBy(sa)) {
|
||||
final int numCardsInHand = p.getCardsIn(ZoneType.Hand).size();
|
||||
@@ -268,9 +269,6 @@ public class DiscardEffect extends SpellAbilityEffect {
|
||||
dPHand = p.getController().chooseCardsToRevealFromHand(amount, amount, dPHand);
|
||||
}
|
||||
|
||||
final String valid = sa.getParamOrDefault("DiscardValid", "Card");
|
||||
CardCollection validCards = CardLists.getValidCards(dPHand, valid, source.getController(), source, sa);
|
||||
|
||||
Player chooser = p;
|
||||
if (mode.endsWith("YouChoose")) {
|
||||
chooser = source.getController();
|
||||
@@ -289,6 +287,9 @@ public class DiscardEffect extends SpellAbilityEffect {
|
||||
continue;
|
||||
}
|
||||
|
||||
final String valid = sa.getParamOrDefault("DiscardValid", "Card");
|
||||
CardCollection validCards = CardLists.getValidCards(dPHand, valid, source.getController(), source, sa);
|
||||
|
||||
int min = sa.hasParam("AnyNumber") || sa.hasParam("Optional") ? 0 : Math.min(validCards.size(), numCards);
|
||||
int max = sa.hasParam("AnyNumber") ? validCards.size() : Math.min(validCards.size(), numCards);
|
||||
|
||||
|
||||
@@ -3,22 +3,19 @@ package forge.game.ability.effects;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import forge.game.ability.SpellAbilityEffect;
|
||||
import forge.game.mana.Mana;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.TargetRestrictions;
|
||||
import forge.util.Lang;
|
||||
|
||||
public class DrainManaEffect extends SpellAbilityEffect {
|
||||
@Override
|
||||
protected String getStackDescription(SpellAbility sa) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
|
||||
final List<Player> tgtPlayers = getTargetPlayers(sa);
|
||||
sb.append(Lang.joinHomogenous(getTargetPlayers(sa)));
|
||||
|
||||
sb.append(StringUtils.join(tgtPlayers, ", "));
|
||||
sb.append(" loses all unspent mana.");
|
||||
|
||||
return sb.toString();
|
||||
@@ -26,13 +23,13 @@ public class DrainManaEffect extends SpellAbilityEffect {
|
||||
|
||||
@Override
|
||||
public void resolve(SpellAbility sa) {
|
||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||
List<Mana> drained = new ArrayList<>();
|
||||
|
||||
for (final Player p : getTargetPlayers(sa)) {
|
||||
if ((tgt == null) || p.canBeTargetedBy(sa)) {
|
||||
drained.addAll(p.getManaPool().clearPool(false));
|
||||
if (!p.isInGame()) {
|
||||
continue;
|
||||
}
|
||||
drained.addAll(p.getManaPool().clearPool(false));
|
||||
}
|
||||
|
||||
if (sa.hasParam("DrainMana")) {
|
||||
|
||||
@@ -62,8 +62,7 @@ public class DrawEffect extends SpellAbilityEffect {
|
||||
moveParams.put(AbilityKey.LastStateGraveyard, sa.getLastStateGraveyard());
|
||||
|
||||
for (final Player p : getDefinedPlayersOrTargeted(sa)) {
|
||||
// TODO can this be removed?
|
||||
if (sa.usesTargeting() && !p.canBeTargetedBy(sa)) {
|
||||
if (!p.isInGame()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -86,7 +86,6 @@ public class FlipOntoBattlefieldEffect extends SpellAbilityEffect {
|
||||
protected String getStackDescription(SpellAbility sa) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
final Card host = sa.getHostCard();
|
||||
final Player p = sa.getActivatingPlayer();
|
||||
|
||||
sb.append("Flip ");
|
||||
sb.append(host.toString());
|
||||
|
||||
@@ -6,7 +6,6 @@ import forge.game.ability.SpellAbilityEffect;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.util.Lang;
|
||||
|
||||
import java.util.List;
|
||||
@@ -36,12 +35,7 @@ public class GoadEffect extends SpellAbilityEffect {
|
||||
|
||||
for (final Card tgtC : getDefinedCardsOrTargeted(sa)) {
|
||||
// only goad things on the battlefield
|
||||
if (!game.getCardsIn(ZoneType.Battlefield).contains(tgtC)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// make sure we can still target now if using targeting
|
||||
if (sa.usesTargeting() && !sa.getTargetRestrictions().canTgtPlayer() && !tgtC.canBeTargetedBy(sa)) {
|
||||
if (!tgtC.isInPlay()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -58,13 +58,14 @@ public class LifeGainEffect extends SpellAbilityEffect {
|
||||
}
|
||||
|
||||
for (final Player p : tgtPlayers) {
|
||||
if (!sa.usesTargeting() || p.canBeTargetedBy(sa)) {
|
||||
if (variableAmount) {
|
||||
sa.setSVar("AFNotDrawnNum", sa.getSVar("AFNotDrawnNum_" + p.getId()));
|
||||
lifeAmount = AbilityUtils.calculateAmount(sa.getHostCard(), amount, sa);
|
||||
}
|
||||
p.gainLife(lifeAmount, sa.getHostCard(), sa);
|
||||
if (!p.isInGame()) {
|
||||
continue;
|
||||
}
|
||||
if (variableAmount) {
|
||||
sa.setSVar("AFNotDrawnNum", sa.getSVar("AFNotDrawnNum_" + p.getId()));
|
||||
lifeAmount = AbilityUtils.calculateAmount(sa.getHostCard(), amount, sa);
|
||||
}
|
||||
p.gainLife(lifeAmount, sa.getHostCard(), sa);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package forge.game.ability.effects;
|
||||
|
||||
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.SpellAbilityEffect;
|
||||
import forge.game.player.Player;
|
||||
@@ -43,9 +42,10 @@ public class LifeLoseEffect extends SpellAbilityEffect {
|
||||
final int lifeAmount = AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("LifeAmount"), sa);
|
||||
|
||||
for (final Player p : getTargetPlayers(sa)) {
|
||||
if (!sa.usesTargeting() || p.canBeTargetedBy(sa)) {
|
||||
lifeLost += p.loseLife(lifeAmount, false, false);
|
||||
if (!p.isInGame()) {
|
||||
continue;
|
||||
}
|
||||
lifeLost += p.loseLife(lifeAmount, false, false);
|
||||
}
|
||||
sa.setSVar("AFLifeLost", "Number$" + lifeLost);
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import forge.game.ability.SpellAbilityEffect;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerCollection;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.TargetRestrictions;
|
||||
import forge.util.Localizer;
|
||||
|
||||
public class LifeSetEffect extends SpellAbilityEffect {
|
||||
@@ -22,29 +21,30 @@ public class LifeSetEffect extends SpellAbilityEffect {
|
||||
public void resolve(SpellAbility sa) {
|
||||
final boolean redistribute = sa.hasParam("Redistribute");
|
||||
final int lifeAmount = redistribute ? 0 : AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("LifeAmount"), sa);
|
||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||
final List<Integer> lifetotals = new ArrayList<>();
|
||||
final PlayerCollection players = getTargetPlayers(sa);
|
||||
|
||||
if (redistribute) {
|
||||
for (final Player p : players) {
|
||||
if (tgt == null || p.canBeTargetedBy(sa)) {
|
||||
lifetotals.add(p.getLife());
|
||||
if (!p.isInGame()) {
|
||||
continue;
|
||||
}
|
||||
lifetotals.add(p.getLife());
|
||||
}
|
||||
}
|
||||
|
||||
for (final Player p : players.threadSafeIterable()) {
|
||||
if (tgt == null || p.canBeTargetedBy(sa)) {
|
||||
if (!redistribute) {
|
||||
p.setLife(lifeAmount, sa);
|
||||
} else {
|
||||
List<Integer> validChoices = getDistribution(players, true, lifetotals);
|
||||
int life = sa.getActivatingPlayer().getController().chooseNumber(sa, Localizer.getInstance().getMessage("lblLifeTotal") + ": " + p, validChoices, p);
|
||||
p.setLife(life, sa);
|
||||
lifetotals.remove((Integer) life);
|
||||
players.remove(p);
|
||||
}
|
||||
if (!p.isInGame()) {
|
||||
continue;
|
||||
}
|
||||
if (!redistribute) {
|
||||
p.setLife(lifeAmount, sa);
|
||||
} else {
|
||||
List<Integer> validChoices = getDistribution(players, true, lifetotals);
|
||||
int life = sa.getActivatingPlayer().getController().chooseNumber(sa, Localizer.getInstance().getMessage("lblLifeTotal") + ": " + p, validChoices, p);
|
||||
p.setLife(life, sa);
|
||||
lifetotals.remove((Integer) life);
|
||||
players.remove(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -87,7 +87,7 @@ public class LifeSetEffect extends SpellAbilityEffect {
|
||||
return validChoices;
|
||||
}
|
||||
}
|
||||
return new ArrayList<Integer>();
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
|
||||
@@ -2,30 +2,18 @@ package forge.game.ability.effects;
|
||||
|
||||
import forge.game.Game;
|
||||
import forge.game.ability.SpellAbilityEffect;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardCollection;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.TargetRestrictions;
|
||||
import forge.util.Lang;
|
||||
|
||||
public class LookAtEffect extends SpellAbilityEffect {
|
||||
|
||||
@Override
|
||||
public void resolve(final SpellAbility sa) {
|
||||
final Card host = sa.getHostCard();
|
||||
final Game game = host.getGame();
|
||||
final Game game = sa.getHostCard().getGame();
|
||||
final Player activator = sa.getActivatingPlayer();
|
||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||
|
||||
final CardCollection targets = new CardCollection();
|
||||
for (final Card tgtCard : getTargetCards(sa)) {
|
||||
if (tgt == null || tgtCard.canBeTargetedBy(sa)) {
|
||||
targets.add(tgtCard);
|
||||
}
|
||||
}
|
||||
|
||||
game.getAction().revealTo(targets, activator);
|
||||
game.getAction().revealTo(getTargetCards(sa), activator);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -48,8 +48,7 @@ public class ManaEffect extends SpellAbilityEffect {
|
||||
final StringBuilder producedMana = new StringBuilder();
|
||||
|
||||
for (Player p : tgtPlayers) {
|
||||
if (sa.usesTargeting() && !p.canBeTargetedBy(sa)) {
|
||||
// Illegal target. Skip.
|
||||
if (!p.isInGame()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,39 +37,37 @@ public class ManifestEffect extends SpellAbilityEffect {
|
||||
moveParams.put(AbilityKey.LastStateGraveyard, lastStateGraveyard);
|
||||
|
||||
for (final Player p : getTargetPlayers(sa, "DefinedPlayer")) {
|
||||
if (sa.usesTargeting() || p.canBeTargetedBy(sa)) {
|
||||
CardCollection tgtCards;
|
||||
if (sa.hasParam("Choices") || sa.hasParam("ChoiceZone")) {
|
||||
ZoneType choiceZone = ZoneType.Hand;
|
||||
if (sa.hasParam("ChoiceZone")) {
|
||||
choiceZone = ZoneType.smartValueOf(sa.getParam("ChoiceZone"));
|
||||
}
|
||||
CardCollection choices = new CardCollection(game.getCardsIn(choiceZone));
|
||||
if (sa.hasParam("Choices")) {
|
||||
choices = CardLists.getValidCards(choices, sa.getParam("Choices"), activator, source, sa);
|
||||
}
|
||||
if (choices.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChooseCardToManifest") + " ";
|
||||
|
||||
tgtCards = new CardCollection(activator.getController().chooseCardsForEffect(choices, sa, title, amount, amount, false, null));
|
||||
} else if ("TopOfLibrary".equals(defined)) {
|
||||
tgtCards = p.getTopXCardsFromLibrary(amount);
|
||||
} else {
|
||||
tgtCards = getTargetCards(sa);
|
||||
CardCollection tgtCards;
|
||||
if (sa.hasParam("Choices") || sa.hasParam("ChoiceZone")) {
|
||||
ZoneType choiceZone = ZoneType.Hand;
|
||||
if (sa.hasParam("ChoiceZone")) {
|
||||
choiceZone = ZoneType.smartValueOf(sa.getParam("ChoiceZone"));
|
||||
}
|
||||
CardCollection choices = new CardCollection(game.getCardsIn(choiceZone));
|
||||
if (sa.hasParam("Choices")) {
|
||||
choices = CardLists.getValidCards(choices, sa.getParam("Choices"), activator, source, sa);
|
||||
}
|
||||
if (choices.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sa.hasParam("Shuffle")) {
|
||||
CardLists.shuffle(tgtCards);
|
||||
}
|
||||
String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChooseCardToManifest") + " ";
|
||||
|
||||
for (Card c : tgtCards) {
|
||||
Card rem = c.manifest(p, sa, moveParams);
|
||||
if (sa.hasParam("RememberManifested") && rem != null && rem.isManifested()) {
|
||||
source.addRemembered(rem);
|
||||
}
|
||||
tgtCards = new CardCollection(activator.getController().chooseCardsForEffect(choices, sa, title, amount, amount, false, null));
|
||||
} else if ("TopOfLibrary".equals(defined)) {
|
||||
tgtCards = p.getTopXCardsFromLibrary(amount);
|
||||
} else {
|
||||
tgtCards = getTargetCards(sa);
|
||||
}
|
||||
|
||||
if (sa.hasParam("Shuffle")) {
|
||||
CardLists.shuffle(tgtCards);
|
||||
}
|
||||
|
||||
for (Card c : tgtCards) {
|
||||
Card rem = c.manifest(p, sa, moveParams);
|
||||
if (sa.hasParam("RememberManifested") && rem != null && rem.isManifested()) {
|
||||
source.addRemembered(rem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,44 +44,46 @@ public class MillEffect extends SpellAbilityEffect {
|
||||
moveParams.put(AbilityKey.LastStateGraveyard, sa.getLastStateGraveyard());
|
||||
|
||||
for (final Player p : getTargetPlayers(sa)) {
|
||||
if (!sa.usesTargeting() || p.canBeTargetedBy(sa)) {
|
||||
if (sa.hasParam("Optional")) {
|
||||
final String prompt = TextUtil.concatWithSpace(Localizer.getInstance().getMessage("lblDoYouWantPutLibraryCardsTo", destination.getTranslatedName()));
|
||||
// CR 701.13b
|
||||
if (numCards > p.getZone(ZoneType.Library).size() || !p.getController().confirmAction(sa, null, prompt, null)) {
|
||||
continue;
|
||||
if (!p.isInGame()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sa.hasParam("Optional")) {
|
||||
final String prompt = TextUtil.concatWithSpace(Localizer.getInstance().getMessage("lblDoYouWantPutLibraryCardsTo", destination.getTranslatedName()));
|
||||
// CR 701.13b
|
||||
if (numCards > p.getZone(ZoneType.Library).size() || !p.getController().confirmAction(sa, null, prompt, null)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
final CardCollectionView milled = p.mill(numCards, destination, bottom, sa, table, moveParams);
|
||||
// Reveal the milled cards, so players don't have to manually inspect the
|
||||
// graveyard to figure out which ones were milled.
|
||||
if (!facedown && reveal) { // do not reveal when exiling face down
|
||||
if (showRevealDialog) {
|
||||
game.getAction().reveal(milled, p, false);
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(p).append(" milled ").append(milled).append(" to ").append(destination);
|
||||
p.getGame().getGameLog().add(GameLogEntryType.ZONE_CHANGE, sb.toString());
|
||||
}
|
||||
if (destination.equals(ZoneType.Exile)) {
|
||||
Card host = sa.getOriginalHost();
|
||||
if (host == null) {
|
||||
host = sa.getHostCard();
|
||||
}
|
||||
for (final Card c : milled) {
|
||||
host.addExiledCard(c);
|
||||
c.setExiledWith(host);
|
||||
if (facedown) {
|
||||
c.turnFaceDown(true);
|
||||
}
|
||||
}
|
||||
final CardCollectionView milled = p.mill(numCards, destination, bottom, sa, table, moveParams);
|
||||
// Reveal the milled cards, so players don't have to manually inspect the
|
||||
// graveyard to figure out which ones were milled.
|
||||
if (!facedown && reveal) { // do not reveal when exiling face down
|
||||
if (showRevealDialog) {
|
||||
game.getAction().reveal(milled, p, false);
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(p).append(" milled ").append(milled).append(" to ").append(destination);
|
||||
p.getGame().getGameLog().add(GameLogEntryType.ZONE_CHANGE, sb.toString());
|
||||
}
|
||||
if (destination.equals(ZoneType.Exile)) {
|
||||
Card host = sa.getOriginalHost();
|
||||
if (host == null) {
|
||||
host = sa.getHostCard();
|
||||
}
|
||||
for (final Card c : milled) {
|
||||
host.addExiledCard(c);
|
||||
c.setExiledWith(host);
|
||||
if (facedown) {
|
||||
c.turnFaceDown(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sa.hasParam("RememberMilled")) {
|
||||
source.addRemembered(milled);
|
||||
}
|
||||
if (sa.hasParam("Imprint")) {
|
||||
source.addImprintedCards(milled);
|
||||
}
|
||||
}
|
||||
if (sa.hasParam("RememberMilled")) {
|
||||
source.addRemembered(milled);
|
||||
}
|
||||
if (sa.hasParam("Imprint")) {
|
||||
source.addImprintedCards(milled);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ import forge.game.card.CardCollectionView;
|
||||
import forge.game.card.CardLists;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.TargetRestrictions;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.util.Aggregates;
|
||||
import forge.util.Localizer;
|
||||
@@ -56,7 +55,6 @@ public class MultiplePilesEffect extends SpellAbilityEffect {
|
||||
|
||||
final String valid = sa.getParamOrDefault("ValidCards", "");
|
||||
|
||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||
final List<Player> tgtPlayers = getTargetPlayers(sa);
|
||||
// starting with the activator
|
||||
int pSize = tgtPlayers.size();
|
||||
@@ -66,28 +64,30 @@ public class MultiplePilesEffect extends SpellAbilityEffect {
|
||||
}
|
||||
|
||||
for (final Player p : tgtPlayers) {
|
||||
if ((tgt == null) || p.canBeTargetedBy(sa)) {
|
||||
CardCollection pool;
|
||||
if (sa.hasParam("DefinedCards")) {
|
||||
pool = AbilityUtils.getDefinedCards(source, sa.getParam("DefinedCards"), sa);
|
||||
} else {
|
||||
pool = new CardCollection(p.getCardsIn(zone));
|
||||
}
|
||||
pool = CardLists.getValidCards(pool, valid, source.getController(), source, sa);
|
||||
|
||||
List<CardCollectionView> pileList = Lists.newArrayList();
|
||||
|
||||
for (int i = 1; i < piles; i++) {
|
||||
int size = pool.size();
|
||||
CardCollectionView pile = p.getController().chooseCardsForEffect(pool, sa, Localizer.getInstance().getMessage("lblChooseCardsInTargetPile", String.valueOf(i)), 0, size, false, null);
|
||||
pileList.add(pile);
|
||||
pool.removeAll(pile);
|
||||
}
|
||||
|
||||
pileList.add(pool);
|
||||
p.getGame().getAction().notifyOfValue(sa, p, pileList.toString(), p);
|
||||
record.put(p, pileList);
|
||||
if (!p.isInGame()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
CardCollection pool;
|
||||
if (sa.hasParam("DefinedCards")) {
|
||||
pool = AbilityUtils.getDefinedCards(source, sa.getParam("DefinedCards"), sa);
|
||||
} else {
|
||||
pool = new CardCollection(p.getCardsIn(zone));
|
||||
}
|
||||
pool = CardLists.getValidCards(pool, valid, source.getController(), source, sa);
|
||||
|
||||
List<CardCollectionView> pileList = Lists.newArrayList();
|
||||
|
||||
for (int i = 1; i < piles; i++) {
|
||||
int size = pool.size();
|
||||
CardCollectionView pile = p.getController().chooseCardsForEffect(pool, sa, Localizer.getInstance().getMessage("lblChooseCardsInTargetPile", String.valueOf(i)), 0, size, false, null);
|
||||
pileList.add(pile);
|
||||
pool.removeAll(pile);
|
||||
}
|
||||
|
||||
pileList.add(pool);
|
||||
p.getGame().getAction().notifyOfValue(sa, p, pileList.toString(), p);
|
||||
record.put(p, pileList);
|
||||
}
|
||||
if (randomChosen) {
|
||||
for (Entry<Player, List<CardCollectionView>> ev : record.entrySet()) {
|
||||
|
||||
@@ -62,13 +62,11 @@ public class MustBlockEffect extends SpellAbilityEffect {
|
||||
long ts = game.getNextTimestamp();
|
||||
|
||||
for (final Card c : tgtCards) {
|
||||
if ((!sa.usesTargeting()) || c.canBeTargetedBy(sa)) {
|
||||
if (mustBlockAll) {
|
||||
c.addMustBlockCards(ts, cards);
|
||||
} else {
|
||||
final Card attacker = cards.get(0);
|
||||
c.addMustBlockCard(ts, attacker);
|
||||
}
|
||||
if (mustBlockAll) {
|
||||
c.addMustBlockCards(ts, cards);
|
||||
} else {
|
||||
final Card attacker = cards.get(0);
|
||||
c.addMustBlockCard(ts, attacker);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,13 +29,16 @@ public class PoisonEffect extends SpellAbilityEffect {
|
||||
final int amount = AbilityUtils.calculateAmount(host, sa.getParam("Num"), sa);
|
||||
|
||||
GameEntityCounterTable table = new GameEntityCounterTable();
|
||||
|
||||
for (final Player p : getTargetPlayers(sa)) {
|
||||
if ((!sa.usesTargeting()) || p.canBeTargetedBy(sa)) {
|
||||
if (amount >= 0) {
|
||||
p.addPoisonCounters(amount, sa.getActivatingPlayer(), table);
|
||||
} else {
|
||||
p.removePoisonCounters(-amount, sa.getActivatingPlayer());
|
||||
}
|
||||
if (!p.isInGame()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (amount >= 0) {
|
||||
p.addPoisonCounters(amount, sa.getActivatingPlayer(), table);
|
||||
} else {
|
||||
p.removePoisonCounters(-amount, sa.getActivatingPlayer());
|
||||
}
|
||||
}
|
||||
table.replaceCounterEffect(game, sa, true);
|
||||
|
||||
@@ -39,7 +39,7 @@ public class ProtectAllEffect extends SpellAbilityEffect {
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
} // protectStackDescription()
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resolve(SpellAbility sa) {
|
||||
@@ -83,27 +83,24 @@ public class ProtectAllEffect extends SpellAbilityEffect {
|
||||
// Deal with permanents
|
||||
final String valid = sa.getParamOrDefault("ValidCards", "");
|
||||
if (!valid.equals("")) {
|
||||
CardCollectionView list = game.getCardsIn(ZoneType.Battlefield);
|
||||
list = CardLists.getValidCards(list, valid, sa.getActivatingPlayer(), host, sa);
|
||||
CardCollectionView list = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), valid, sa.getActivatingPlayer(), host, sa);
|
||||
|
||||
for (final Card tgtC : list) {
|
||||
if (tgtC.isInPlay()) {
|
||||
tgtC.addChangedCardKeywords(gainsKWList, null, false, timestamp, 0, true);
|
||||
tgtC.addChangedCardKeywords(gainsKWList, null, false, timestamp, 0, true);
|
||||
|
||||
if (!"Permanent".equals(sa.getParam("Duration"))) {
|
||||
// If not Permanent, remove protection at EOT
|
||||
final GameCommand untilEOT = new GameCommand() {
|
||||
private static final long serialVersionUID = -6573962672873853565L;
|
||||
if (!"Permanent".equals(sa.getParam("Duration"))) {
|
||||
// If not Permanent, remove protection at EOT
|
||||
final GameCommand untilEOT = new GameCommand() {
|
||||
private static final long serialVersionUID = -6573962672873853565L;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (tgtC.isInPlay()) {
|
||||
tgtC.removeChangedCardKeywords(timestamp, 0, true);
|
||||
}
|
||||
@Override
|
||||
public void run() {
|
||||
if (tgtC.isInPlay()) {
|
||||
tgtC.removeChangedCardKeywords(timestamp, 0, true);
|
||||
}
|
||||
};
|
||||
addUntilCommand(sa, untilEOT);
|
||||
}
|
||||
}
|
||||
};
|
||||
addUntilCommand(sa, untilEOT);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -111,11 +108,8 @@ public class ProtectAllEffect extends SpellAbilityEffect {
|
||||
// Deal with Players
|
||||
final String players = sa.getParamOrDefault("ValidPlayers", "");
|
||||
if (!players.equals("")) {
|
||||
final List<Player> playerList = AbilityUtils.getDefinedPlayers(host, players, sa);
|
||||
for (final Player player : playerList) {
|
||||
for (final String gain : gains) {
|
||||
player.addChangedKeywords(ImmutableList.of("Protection from " + gain), ImmutableList.of(), timestamp, 0);
|
||||
}
|
||||
for (final Player player : AbilityUtils.getDefinedPlayers(host, players, sa)) {
|
||||
player.addChangedKeywords(gainsKWList, ImmutableList.of(), timestamp, 0);
|
||||
|
||||
if (!"Permanent".equals(sa.getParam("Duration"))) {
|
||||
// If not Permanent, remove protection at EOT
|
||||
|
||||
@@ -90,7 +90,7 @@ public class ProtectEffect extends SpellAbilityEffect {
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
} // protectStackDescription()
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resolve(SpellAbility sa) {
|
||||
@@ -140,11 +140,6 @@ public class ProtectEffect extends SpellAbilityEffect {
|
||||
continue;
|
||||
}
|
||||
|
||||
// if this is a target, make sure we can still target now
|
||||
if (sa.usesTargeting() && !tgtC.canBeTargetedBy(sa)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
tgtC.addChangedCardKeywords(gainsKWList, null, false, timestamp, 0, true);
|
||||
|
||||
if (!"Permanent".equals(sa.getParam("Duration"))) {
|
||||
@@ -186,7 +181,7 @@ public class ProtectEffect extends SpellAbilityEffect {
|
||||
addUntilCommand(sa, untilEOT);
|
||||
}
|
||||
}
|
||||
} // protectResolve()
|
||||
}
|
||||
|
||||
public static List<String> getProtectionList(final SpellAbility sa) {
|
||||
final List<String> gains = new ArrayList<>();
|
||||
|
||||
@@ -199,7 +199,7 @@ public class PumpEffect extends SpellAbilityEffect {
|
||||
sb.append(" ");
|
||||
}
|
||||
|
||||
if (sa instanceof AbilitySub & sa.getRootAbility().getTargets().containsAll(tgts)) {
|
||||
if (sa instanceof AbilitySub && sa.getRootAbility().getTargets().containsAll(tgts)) {
|
||||
//try to avoid having the same long list of targets twice in a StackDescription
|
||||
sb.append(tgts.size() == 1 && tgts.get(0) instanceof Card ? "It " : "They ");
|
||||
} else {
|
||||
@@ -266,7 +266,7 @@ public class PumpEffect extends SpellAbilityEffect {
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
} // pumpStackDescription()
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resolve(final SpellAbility sa) {
|
||||
@@ -274,7 +274,6 @@ public class PumpEffect extends SpellAbilityEffect {
|
||||
final Game game = activator.getGame();
|
||||
final Card host = sa.getHostCard();
|
||||
final long timestamp = game.getNextTimestamp();
|
||||
List<GameEntity> tgts = Lists.newArrayList();
|
||||
List<Card> tgtCards = getCardsfromTargets(sa);
|
||||
List<Player> tgtPlayers = getTargetPlayers(sa);
|
||||
|
||||
@@ -296,8 +295,6 @@ public class PumpEffect extends SpellAbilityEffect {
|
||||
keywords = CardFactoryUtil.sharedKeywords(keywords, restrictions, zones, host, sa);
|
||||
}
|
||||
|
||||
tgts.addAll(tgtCards);
|
||||
tgts.addAll(tgtPlayers);
|
||||
final CardCollection untargetedCards = CardUtil.getRadiance(sa);
|
||||
|
||||
if (sa.hasParam("DefinedKW")) {
|
||||
@@ -433,11 +430,6 @@ public class PumpEffect extends SpellAbilityEffect {
|
||||
continue;
|
||||
}
|
||||
|
||||
// if pump is a target, make sure we can still target now
|
||||
if (sa.usesTargeting() && !tgtC.canBeTargetedBy(sa)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// substitute specific tgtC mana cost for keyword placeholder CardManaCost
|
||||
List<String> affectedKeywords = Lists.newArrayList(keywords);
|
||||
|
||||
@@ -486,7 +478,7 @@ public class PumpEffect extends SpellAbilityEffect {
|
||||
}
|
||||
|
||||
for (Player p : tgtPlayers) {
|
||||
if (!p.canBeTargetedBy(sa)) {
|
||||
if (!p.isInGame()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -494,5 +486,5 @@ public class PumpEffect extends SpellAbilityEffect {
|
||||
}
|
||||
|
||||
replaceDying(sa);
|
||||
} // pumpResolve()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ import forge.game.card.CardCollection;
|
||||
import forge.game.card.CardCollectionView;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.TargetRestrictions;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.util.Lang;
|
||||
import forge.util.Localizer;
|
||||
@@ -70,19 +69,15 @@ public class RearrangeTopOfLibraryEffect extends SpellAbilityEffect {
|
||||
|
||||
@Override
|
||||
public void resolve(SpellAbility sa) {
|
||||
int numCards = 0;
|
||||
Card host = sa.getHostCard();
|
||||
boolean shuffle = false;
|
||||
|
||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||
|
||||
numCards = AbilityUtils.calculateAmount(host, sa.getParam("NumCards"), sa);
|
||||
shuffle = sa.hasParam("MayShuffle");
|
||||
int numCards = AbilityUtils.calculateAmount(host, sa.getParam("NumCards"), sa);
|
||||
boolean shuffle = sa.hasParam("MayShuffle");
|
||||
|
||||
for (final Player p : getTargetPlayers(sa)) {
|
||||
if ((tgt == null) || p.canBeTargetedBy(sa)) {
|
||||
rearrangeTopOfLibrary(host, p, numCards, shuffle, sa);
|
||||
if (!p.isInGame()) {
|
||||
continue;
|
||||
}
|
||||
rearrangeTopOfLibrary(host, p, numCards, shuffle, sa);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ import forge.game.card.CardCollection;
|
||||
import forge.game.combat.Combat;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.TargetRestrictions;
|
||||
|
||||
public class RemoveFromCombatEffect extends SpellAbilityEffect {
|
||||
|
||||
@@ -34,37 +33,38 @@ public class RemoveFromCombatEffect extends SpellAbilityEffect {
|
||||
final Player activator = sa.getActivatingPlayer();
|
||||
final Game game = activator.getGame();
|
||||
final boolean rem = sa.hasParam("RememberRemovedFromCombat");
|
||||
final Combat combat = game.getPhaseHandler().getCombat();
|
||||
|
||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||
for (final Card c : getTargetCards(sa)) {
|
||||
final Combat combat = game.getPhaseHandler().getCombat();
|
||||
if (combat != null && (tgt == null || c.canBeTargetedBy(sa))) {
|
||||
// Unblock creatures that were blocked only by this card (e.g. Ydwen Efreet)
|
||||
if (sa.hasParam("UnblockCreaturesBlockedOnlyBy")) {
|
||||
CardCollection attackers = AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam("UnblockCreaturesBlockedOnlyBy"), sa);
|
||||
if (!attackers.isEmpty()) {
|
||||
CardCollection blockedByCard = combat.getAttackersBlockedBy(attackers.getFirst());
|
||||
for (Card atk : blockedByCard) {
|
||||
boolean blockedOnlyByCard = true;
|
||||
for (Card blocker : combat.getBlockers(atk)) {
|
||||
if (!blocker.equals(attackers.getFirst())) {
|
||||
blockedOnlyByCard = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (blockedOnlyByCard) {
|
||||
combat.setBlocked(atk, false);
|
||||
if (combat == null || !c.isInPlay()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Unblock creatures that were blocked only by this card (e.g. Ydwen Efreet)
|
||||
if (sa.hasParam("UnblockCreaturesBlockedOnlyBy")) {
|
||||
CardCollection attackers = AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam("UnblockCreaturesBlockedOnlyBy"), sa);
|
||||
if (!attackers.isEmpty()) {
|
||||
CardCollection blockedByCard = combat.getAttackersBlockedBy(attackers.getFirst());
|
||||
for (Card atk : blockedByCard) {
|
||||
boolean blockedOnlyByCard = true;
|
||||
for (Card blocker : combat.getBlockers(atk)) {
|
||||
if (!blocker.equals(attackers.getFirst())) {
|
||||
blockedOnlyByCard = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (blockedOnlyByCard) {
|
||||
combat.setBlocked(atk, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
game.getCombat().saveLKI(c);
|
||||
combat.removeFromCombat(c);
|
||||
game.getCombat().saveLKI(c);
|
||||
combat.removeFromCombat(c);
|
||||
|
||||
if (rem) {
|
||||
sa.getHostCard().addRemembered(c);
|
||||
}
|
||||
if (rem) {
|
||||
sa.getHostCard().addRemembered(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import forge.game.ability.SpellAbilityEffect;
|
||||
import forge.game.card.CardCollection;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.TargetRestrictions;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.util.Lang;
|
||||
import forge.util.MyRandom;
|
||||
@@ -26,17 +25,18 @@ public class ReorderZoneEffect extends SpellAbilityEffect {
|
||||
public void resolve(SpellAbility sa) {
|
||||
final ZoneType zone = ZoneType.smartValueOf(sa.getParam("Zone"));
|
||||
boolean shuffle = sa.hasParam("Random");
|
||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||
|
||||
for (final Player p : getTargetPlayers(sa)) {
|
||||
if ((tgt == null) || p.canBeTargetedBy(sa)) {
|
||||
CardCollection list = new CardCollection(p.getCardsIn(zone));
|
||||
if (shuffle) {
|
||||
Collections.shuffle(list, MyRandom.getRandom());
|
||||
p.getZone(zone).setCards(list);
|
||||
} else {
|
||||
p.getController().orderMoveToZoneList(list, zone, sa);
|
||||
}
|
||||
if (!p.isInGame()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
CardCollection list = new CardCollection(p.getCardsIn(zone));
|
||||
if (shuffle) {
|
||||
Collections.shuffle(list, MyRandom.getRandom());
|
||||
p.getZone(zone).setCards(list);
|
||||
} else {
|
||||
p.getController().orderMoveToZoneList(list, zone, sa);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,76 +29,77 @@ public class RevealEffect extends SpellAbilityEffect {
|
||||
int cnt = sa.hasParam("NumCards") ? AbilityUtils.calculateAmount(host, sa.getParam("NumCards"), sa) : 1;
|
||||
|
||||
for (final Player p : getTargetPlayers(sa)) {
|
||||
if (!sa.usesTargeting() || p.canBeTargetedBy(sa)) {
|
||||
final CardCollectionView cardsInHand = p.getZone(ZoneType.Hand).getCards();
|
||||
if (cardsInHand.isEmpty()) {
|
||||
if (!p.isInGame()) {
|
||||
continue;
|
||||
}
|
||||
final CardCollectionView cardsInHand = p.getZone(ZoneType.Hand).getCards();
|
||||
if (cardsInHand.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
final CardCollection revealed = new CardCollection();
|
||||
if (sa.hasParam("Random")) {
|
||||
CardCollection valid = new CardCollection(cardsInHand);
|
||||
|
||||
if (sa.hasParam("RevealValid")) {
|
||||
valid = CardLists.getValidCards(valid, sa.getParam("RevealValid"), p, host, sa);
|
||||
}
|
||||
|
||||
if (valid.isEmpty())
|
||||
continue;
|
||||
}
|
||||
final CardCollection revealed = new CardCollection();
|
||||
if (sa.hasParam("Random")) {
|
||||
CardCollection valid = new CardCollection(cardsInHand);
|
||||
|
||||
if (sa.hasParam("RevealValid")) {
|
||||
valid = CardLists.getValidCards(valid, sa.getParam("RevealValid"), p, host, sa);
|
||||
if (sa.hasParam("NumCards")) {
|
||||
final int revealnum = Math.min(cardsInHand.size(), cnt);
|
||||
for (int i = 0; i < revealnum; i++) {
|
||||
final Card random = Aggregates.random(valid);
|
||||
revealed.add(random);
|
||||
valid.remove(random);
|
||||
}
|
||||
|
||||
if (valid.isEmpty())
|
||||
continue;
|
||||
|
||||
if (sa.hasParam("NumCards")) {
|
||||
final int revealnum = Math.min(cardsInHand.size(), cnt);
|
||||
for (int i = 0; i < revealnum; i++) {
|
||||
final Card random = Aggregates.random(valid);
|
||||
revealed.add(random);
|
||||
valid.remove(random);
|
||||
}
|
||||
} else {
|
||||
revealed.add(Aggregates.random(valid));
|
||||
}
|
||||
|
||||
} else if (sa.hasParam("RevealDefined")) {
|
||||
revealed.addAll(AbilityUtils.getDefinedCards(host, sa.getParam("RevealDefined"), sa));
|
||||
} else if (sa.hasParam("RevealAllValid")) {
|
||||
revealed.addAll(CardLists.getValidCards(cardsInHand, sa.getParam("RevealAllValid"), p, host, sa));
|
||||
} else {
|
||||
CardCollection valid = new CardCollection(cardsInHand);
|
||||
|
||||
if (sa.hasParam("RevealValid")) {
|
||||
valid = CardLists.getValidCards(valid, sa.getParam("RevealValid"), p, host, sa);
|
||||
}
|
||||
|
||||
if (valid.isEmpty())
|
||||
continue;
|
||||
|
||||
if (sa.hasParam("RevealAll")) { //for when cards to reveal are not in hand
|
||||
revealed.addAll(valid);
|
||||
} else {
|
||||
if (cnt > valid.size())
|
||||
cnt = valid.size();
|
||||
|
||||
int min = cnt;
|
||||
if (anyNumber) {
|
||||
cnt = valid.size();
|
||||
min = 0;
|
||||
} else if (optional) {
|
||||
min = 0;
|
||||
}
|
||||
|
||||
revealed.addAll(p.getController().chooseCardsToRevealFromHand(min, cnt, valid));
|
||||
}
|
||||
revealed.add(Aggregates.random(valid));
|
||||
}
|
||||
|
||||
if (sa.hasParam("RevealToAll") || sa.hasParam("Random")) {
|
||||
game.getAction().reveal(revealed, p, false,
|
||||
sa.getParamOrDefault("RevealTitle", ""));
|
||||
} else if (sa.hasParam("RevealDefined")) {
|
||||
revealed.addAll(AbilityUtils.getDefinedCards(host, sa.getParam("RevealDefined"), sa));
|
||||
} else if (sa.hasParam("RevealAllValid")) {
|
||||
revealed.addAll(CardLists.getValidCards(cardsInHand, sa.getParam("RevealAllValid"), p, host, sa));
|
||||
} else {
|
||||
CardCollection valid = new CardCollection(cardsInHand);
|
||||
|
||||
if (sa.hasParam("RevealValid")) {
|
||||
valid = CardLists.getValidCards(valid, sa.getParam("RevealValid"), p, host, sa);
|
||||
}
|
||||
|
||||
if (valid.isEmpty())
|
||||
continue;
|
||||
|
||||
if (sa.hasParam("RevealAll")) { //for when cards to reveal are not in hand
|
||||
revealed.addAll(valid);
|
||||
} else {
|
||||
game.getAction().reveal(revealed, p);
|
||||
}
|
||||
for (final Card c : revealed) {
|
||||
game.getTriggerHandler().runTrigger(TriggerType.Revealed, AbilityKey.mapFromCard(c), false);
|
||||
if (sa.hasParam("RememberRevealed")) {
|
||||
host.addRemembered(c);
|
||||
if (cnt > valid.size())
|
||||
cnt = valid.size();
|
||||
|
||||
int min = cnt;
|
||||
if (anyNumber) {
|
||||
cnt = valid.size();
|
||||
min = 0;
|
||||
} else if (optional) {
|
||||
min = 0;
|
||||
}
|
||||
|
||||
revealed.addAll(p.getController().chooseCardsToRevealFromHand(min, cnt, valid));
|
||||
}
|
||||
}
|
||||
|
||||
if (sa.hasParam("RevealToAll") || sa.hasParam("Random")) {
|
||||
game.getAction().reveal(revealed, p, false,
|
||||
sa.getParamOrDefault("RevealTitle", ""));
|
||||
} else {
|
||||
game.getAction().reveal(revealed, p);
|
||||
}
|
||||
for (final Card c : revealed) {
|
||||
game.getTriggerHandler().runTrigger(TriggerType.Revealed, AbilityKey.mapFromCard(c), false);
|
||||
if (sa.hasParam("RememberRevealed")) {
|
||||
host.addRemembered(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import forge.game.ability.SpellAbilityEffect;
|
||||
import forge.game.card.*;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.TargetRestrictions;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.util.Lang;
|
||||
import forge.util.Localizer;
|
||||
@@ -36,33 +35,32 @@ public class RevealHandEffect extends SpellAbilityEffect {
|
||||
@Override
|
||||
public void resolve(SpellAbility sa) {
|
||||
final Card host = sa.getHostCard();
|
||||
|
||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||
final boolean optional = sa.hasParam("Optional");
|
||||
|
||||
for (final Player p : getTargetPlayers(sa)) {
|
||||
if ((tgt == null) || p.canBeTargetedBy(sa)) {
|
||||
if (optional && !p.getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblDoYouWantRevealYourHand"), null)) {
|
||||
continue;
|
||||
}
|
||||
CardCollectionView hand = p.getCardsIn(ZoneType.Hand);
|
||||
if (sa.hasParam("RevealType")) {
|
||||
hand = CardLists.getType(hand, sa.getParam("RevealType"));
|
||||
}
|
||||
if (sa.hasParam("Look")) {
|
||||
sa.getActivatingPlayer().getController().reveal(hand, ZoneType.Hand, p);
|
||||
} else {
|
||||
host.getGame().getAction().reveal(hand, p);
|
||||
}
|
||||
if (sa.hasParam("RememberRevealed")) {
|
||||
host.addRemembered(hand);
|
||||
}
|
||||
if (sa.hasParam("ImprintRevealed")) {
|
||||
host.addImprintedCards(hand);
|
||||
}
|
||||
if (sa.hasParam("RememberRevealedPlayer")) {
|
||||
host.addRemembered(p);
|
||||
}
|
||||
if (!p.isInGame()) {
|
||||
continue;
|
||||
}
|
||||
if (optional && !p.getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblDoYouWantRevealYourHand"), null)) {
|
||||
continue;
|
||||
}
|
||||
CardCollectionView hand = p.getCardsIn(ZoneType.Hand);
|
||||
if (sa.hasParam("RevealType")) {
|
||||
hand = CardLists.getType(hand, sa.getParam("RevealType"));
|
||||
}
|
||||
if (sa.hasParam("Look")) {
|
||||
sa.getActivatingPlayer().getController().reveal(hand, ZoneType.Hand, p);
|
||||
} else {
|
||||
host.getGame().getAction().reveal(hand, p);
|
||||
}
|
||||
if (sa.hasParam("RememberRevealed")) {
|
||||
host.addRemembered(hand);
|
||||
}
|
||||
if (sa.hasParam("ImprintRevealed")) {
|
||||
host.addImprintedCards(hand);
|
||||
}
|
||||
if (sa.hasParam("RememberRevealedPlayer")) {
|
||||
host.addRemembered(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,8 +43,10 @@ public class ScryEffect extends SpellAbilityEffect {
|
||||
|
||||
// Optional here for spells that have optional multi-player scrying
|
||||
for (final Player p : getTargetPlayers(sa)) {
|
||||
if ( (!sa.usesTargeting() || p.canBeTargetedBy(sa)) &&
|
||||
(!isOptional || p.getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblDoYouWanttoScry"), null)) ) {
|
||||
if (!p.isInGame()) {
|
||||
continue;
|
||||
}
|
||||
if (!isOptional || p.getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblDoYouWanttoScry"), null)) {
|
||||
players.add(p);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,10 +93,6 @@ public class SetStateEffect extends SpellAbilityEffect {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sa.usesTargeting() && !gameCard.canBeTargetedBy(sa)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Cards which are not on the battlefield should not be able to transform.
|
||||
// TurnFace should be allowed in other zones like Exile too
|
||||
// Specialize and Unspecialize are allowed in other zones
|
||||
|
||||
@@ -6,7 +6,6 @@ import java.util.List;
|
||||
import forge.game.ability.SpellAbilityEffect;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.TargetRestrictions;
|
||||
import forge.util.Localizer;
|
||||
|
||||
public class ShuffleEffect extends SpellAbilityEffect {
|
||||
@@ -15,16 +14,13 @@ public class ShuffleEffect extends SpellAbilityEffect {
|
||||
public void resolve(SpellAbility sa) {
|
||||
final boolean optional = sa.hasParam("Optional");
|
||||
|
||||
final List<Player> tgtPlayers = getTargetPlayers(sa);
|
||||
|
||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||
|
||||
for (final Player p : tgtPlayers) {
|
||||
if ((tgt == null) || p.canBeTargetedBy(sa)) {
|
||||
boolean mustShuffle = !optional || sa.getActivatingPlayer().getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblHaveTargetShuffle", p.getName()), null);
|
||||
if (mustShuffle)
|
||||
p.shuffle(sa);
|
||||
for (final Player p : getTargetPlayers(sa)) {
|
||||
if (!p.isInGame()) {
|
||||
continue;
|
||||
}
|
||||
boolean mustShuffle = !optional || sa.getActivatingPlayer().getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblHaveTargetShuffle", p.getName()), null);
|
||||
if (mustShuffle)
|
||||
p.shuffle(sa);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,13 +42,14 @@ public class SurveilEffect extends SpellAbilityEffect {
|
||||
moveParams.put(AbilityKey.LastStateGraveyard, sa.getLastStateGraveyard());
|
||||
|
||||
for (final Player p : getTargetPlayers(sa)) {
|
||||
if (!sa.usesTargeting() || p.canBeTargetedBy(sa)) {
|
||||
if (isOptional && !p.getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblDoYouWantSurveil"), null)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
p.surveil(num, sa, table, moveParams);
|
||||
if (!p.isInGame()) {
|
||||
continue;
|
||||
}
|
||||
if (isOptional && !p.getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblDoYouWantSurveil"), null)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
p.surveil(num, sa, table, moveParams);
|
||||
}
|
||||
table.triggerChangesZoneAll(sa.getHostCard().getGame(), sa);
|
||||
}
|
||||
|
||||
@@ -27,9 +27,11 @@ public class TakeInitiativeEffect extends SpellAbilityEffect {
|
||||
final String set = sa.getHostCard().getSetCode();
|
||||
|
||||
for (final Player p : getTargetPlayers(sa)) {
|
||||
if (!sa.usesTargeting() || p.canBeTargetedBy(sa)) {
|
||||
p.getGame().getAction().takeInitiative(p, set);
|
||||
if (!p.isInGame()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
p.getGame().getAction().takeInitiative(p, set);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
package forge.game.ability.effects;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import forge.game.Game;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.SpellAbilityEffect;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardCollection;
|
||||
import forge.game.card.CardCollectionView;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.AbilitySub;
|
||||
@@ -34,17 +31,10 @@ public class TapAllEffect extends SpellAbilityEffect {
|
||||
}
|
||||
|
||||
CardCollectionView cards;
|
||||
|
||||
final List<Player> tgtPlayers = getTargetPlayers(sa);
|
||||
|
||||
if (!sa.usesTargeting() && !sa.hasParam("Defined")) {
|
||||
cards = game.getCardsIn(ZoneType.Battlefield);
|
||||
} else {
|
||||
CardCollection cards2 = new CardCollection();
|
||||
for (final Player p : tgtPlayers) {
|
||||
cards2.addAll(p.getCardsIn(ZoneType.Battlefield));
|
||||
}
|
||||
cards = cards2;
|
||||
cards = getTargetPlayers(sa).getCardsIn(ZoneType.Battlefield);
|
||||
}
|
||||
|
||||
cards = AbilityUtils.filterListByType(cards, sa.getParam("ValidCards"), sa);
|
||||
|
||||
@@ -23,9 +23,6 @@ public class TapEffect extends SpellAbilityEffect {
|
||||
if (tgtC.isPhasedOut()) {
|
||||
continue;
|
||||
}
|
||||
if (sa.usesTargeting() && !tgtC.canBeTargetedBy(sa)) {
|
||||
continue;
|
||||
}
|
||||
if (tgtC.isInPlay()) {
|
||||
if (tgtC.isUntapped() && remTapped || alwaysRem) {
|
||||
card.addRemembered(tgtC);
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
package forge.game.ability.effects;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import forge.game.Game;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
@@ -14,9 +11,8 @@ import forge.game.player.Player;
|
||||
import forge.game.player.PlayerController;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.util.Lang;
|
||||
import forge.util.Localizer;
|
||||
import forge.util.collect.FCollection;
|
||||
|
||||
|
||||
public class TapOrUntapAllEffect extends SpellAbilityEffect {
|
||||
|
||||
@@ -29,8 +25,7 @@ public class TapOrUntapAllEffect extends SpellAbilityEffect {
|
||||
if (sa.hasParam("ValidMessage")) {
|
||||
sb.append(sa.getParam("ValidMessage"));
|
||||
} else {
|
||||
final List<Card> tgtCards = getTargetCards(sa);
|
||||
sb.append(StringUtils.join(tgtCards, ", "));
|
||||
sb.append(Lang.joinHomogenous(getTargetCards(sa)));
|
||||
}
|
||||
sb.append(".");
|
||||
return sb.toString();
|
||||
@@ -38,19 +33,18 @@ public class TapOrUntapAllEffect extends SpellAbilityEffect {
|
||||
|
||||
@Override
|
||||
public void resolve(SpellAbility sa) {
|
||||
CardCollectionView validCards = getTargetCards(sa);
|
||||
final Player activator = sa.getActivatingPlayer();
|
||||
final Game game = activator.getGame();
|
||||
|
||||
FCollection<Player> targetedPlayers = getTargetPlayers(sa);
|
||||
|
||||
CardCollectionView validCards;
|
||||
if (sa.hasParam("ValidCards")) {
|
||||
validCards = game.getCardsIn(ZoneType.Battlefield);
|
||||
validCards = AbilityUtils.filterListByType(validCards, sa.getParam("ValidCards"), sa);
|
||||
validCards = AbilityUtils.filterListByType(game.getCardsIn(ZoneType.Battlefield), sa.getParam("ValidCards"), sa);
|
||||
} else {
|
||||
validCards = getTargetCards(sa);
|
||||
}
|
||||
|
||||
if (sa.usesTargeting() || sa.hasParam("Defined")) {
|
||||
validCards = CardLists.filterControlledBy(validCards, targetedPlayers);
|
||||
validCards = CardLists.filterControlledBy(validCards, getTargetPlayers(sa));
|
||||
}
|
||||
|
||||
// Default to tapping for AI
|
||||
@@ -66,13 +60,14 @@ public class TapOrUntapAllEffect extends SpellAbilityEffect {
|
||||
|
||||
toTap = sa.getActivatingPlayer().getController().chooseBinary(sa, sb.toString(), PlayerController.BinaryChoiceType.TapOrUntap);
|
||||
|
||||
for (final Card cad : validCards) {
|
||||
if (cad.isInPlay()) {
|
||||
if (toTap) {
|
||||
cad.tap(true);
|
||||
} else {
|
||||
cad.untap(true);
|
||||
}
|
||||
for (final Card tgtC : validCards) {
|
||||
if (!tgtC.isInPlay()) {
|
||||
continue;
|
||||
}
|
||||
if (toTap) {
|
||||
tgtC.tap(true);
|
||||
} else {
|
||||
tgtC.untap(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,14 +2,12 @@ package forge.game.ability.effects;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import forge.game.ability.SpellAbilityEffect;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.player.PlayerController;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.TargetRestrictions;
|
||||
import forge.util.CardTranslation;
|
||||
import forge.util.Lang;
|
||||
import forge.util.Localizer;
|
||||
|
||||
public class TapOrUntapEffect extends SpellAbilityEffect {
|
||||
@@ -24,8 +22,7 @@ public class TapOrUntapEffect extends SpellAbilityEffect {
|
||||
|
||||
sb.append("Tap or untap ");
|
||||
|
||||
final List<Card> tgtCards = getTargetCards(sa);
|
||||
sb.append(StringUtils.join(tgtCards, ", "));
|
||||
sb.append(Lang.joinHomogenous(getTargetCards(sa)));
|
||||
sb.append(".");
|
||||
return sb.toString();
|
||||
}
|
||||
@@ -33,24 +30,24 @@ public class TapOrUntapEffect extends SpellAbilityEffect {
|
||||
@Override
|
||||
public void resolve(SpellAbility sa) {
|
||||
final List<Card> tgtCards = getTargetCards(sa);
|
||||
|
||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||
PlayerController pc = sa.getActivatingPlayer().getController();
|
||||
|
||||
for (final Card tgtC : tgtCards) {
|
||||
if (!tgtC.isInPlay()) {
|
||||
continue;
|
||||
}
|
||||
if (tgtC.isPhasedOut()) {
|
||||
continue;
|
||||
}
|
||||
if (tgtC.isInPlay() && ((tgt == null) || tgtC.canBeTargetedBy(sa))) {
|
||||
// If the effected card is controlled by the same controller of the SA, default to untap.
|
||||
boolean tap = pc.chooseBinary(sa, Localizer.getInstance().getMessage("lblTapOrUntapTarget", CardTranslation.getTranslatedName(tgtC.getName())), PlayerController.BinaryChoiceType.TapOrUntap,
|
||||
!tgtC.getController().equals(sa.getActivatingPlayer()) );
|
||||
|
||||
if (tap) {
|
||||
tgtC.tap(true);
|
||||
} else {
|
||||
tgtC.untap(true);
|
||||
}
|
||||
// If the effected card is controlled by the same controller of the SA, default to untap.
|
||||
boolean tap = pc.chooseBinary(sa, Localizer.getInstance().getMessage("lblTapOrUntapTarget", CardTranslation.getTranslatedName(tgtC.getName())), PlayerController.BinaryChoiceType.TapOrUntap,
|
||||
!tgtC.getController().equals(sa.getActivatingPlayer()) );
|
||||
|
||||
if (tap) {
|
||||
tgtC.tap(true);
|
||||
} else {
|
||||
tgtC.untap(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ import forge.game.card.CardCollectionView;
|
||||
import forge.game.card.CardLists;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.TargetRestrictions;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.util.Lang;
|
||||
import forge.util.Localizer;
|
||||
@@ -26,15 +25,11 @@ public class TwoPilesEffect extends SpellAbilityEffect {
|
||||
protected String getStackDescription(SpellAbility sa) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
|
||||
final List<Player> tgtPlayers = getTargetPlayers(sa);
|
||||
|
||||
final String valid = sa.getParamOrDefault("ValidCards", "");
|
||||
|
||||
sb.append("Separate all ").append(valid).append(" cards ");
|
||||
|
||||
for (final Player p : tgtPlayers) {
|
||||
sb.append(p).append(" ");
|
||||
}
|
||||
sb.append(Lang.joinHomogenous(getTargetPlayers(sa)));
|
||||
sb.append("controls into two piles.");
|
||||
return sb.toString();
|
||||
}
|
||||
@@ -55,7 +50,6 @@ public class TwoPilesEffect extends SpellAbilityEffect {
|
||||
|
||||
final String valid = sa.getParamOrDefault("ValidCards", "Card");
|
||||
|
||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||
final List<Player> tgtPlayers = getTargetPlayers(sa);
|
||||
|
||||
Player separator = card.getController();
|
||||
@@ -75,116 +69,118 @@ public class TwoPilesEffect extends SpellAbilityEffect {
|
||||
}
|
||||
|
||||
for (final Player p : tgtPlayers) {
|
||||
if ((tgt == null) || p.canBeTargetedBy(sa)) {
|
||||
CardCollectionView pool0;
|
||||
if (sa.hasParam("DefinedCards")) {
|
||||
pool0 = AbilityUtils.getDefinedCards(card, sa.getParam("DefinedCards"), sa);
|
||||
} else {
|
||||
pool0 = p.getCardsIn(zone);
|
||||
}
|
||||
CardCollection pool = CardLists.getValidCards(pool0, valid, card.getController(), card, sa);
|
||||
int size = pool.size();
|
||||
if (size == 0) {
|
||||
return;
|
||||
}
|
||||
if (!p.isInGame()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String title;
|
||||
if ("One".equals(sa.getParamOrDefault("FaceDown", "False"))) {
|
||||
title = Localizer.getInstance().getMessage("lblSelectCardForFaceDownPile");
|
||||
} else if (isLeftRightPile) {
|
||||
title = Localizer.getInstance().getMessage("lblSelectCardForLeftPile");
|
||||
} else {
|
||||
title = Localizer.getInstance().getMessage("lblDivideCardIntoTwoPiles");
|
||||
}
|
||||
CardCollectionView pool0;
|
||||
if (sa.hasParam("DefinedCards")) {
|
||||
pool0 = AbilityUtils.getDefinedCards(card, sa.getParam("DefinedCards"), sa);
|
||||
} else {
|
||||
pool0 = p.getCardsIn(zone);
|
||||
}
|
||||
CardCollection pool = CardLists.getValidCards(pool0, valid, card.getController(), card, sa);
|
||||
int size = pool.size();
|
||||
if (size == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// first, separate the cards into piles
|
||||
final CardCollectionView pile1;
|
||||
final CardCollection pile2;
|
||||
if (sa.hasParam("DefinedPiles")) {
|
||||
final String[] def = sa.getParam("DefinedPiles").split(",", 2);
|
||||
pile1 = AbilityUtils.getDefinedCards(card, def[0], sa);
|
||||
pile2 = AbilityUtils.getDefinedCards(card, def[1], sa);
|
||||
} else {
|
||||
pile1 = separator.getController().chooseCardsForEffect(pool, sa, title, 0, size, false, null);
|
||||
pile2 = new CardCollection(pool);
|
||||
pile2.removeAll(pile1);
|
||||
}
|
||||
String title;
|
||||
if ("One".equals(sa.getParamOrDefault("FaceDown", "False"))) {
|
||||
title = Localizer.getInstance().getMessage("lblSelectCardForFaceDownPile");
|
||||
} else if (isLeftRightPile) {
|
||||
title = Localizer.getInstance().getMessage("lblSelectCardForLeftPile");
|
||||
} else {
|
||||
title = Localizer.getInstance().getMessage("lblDivideCardIntoTwoPiles");
|
||||
}
|
||||
|
||||
if (isLeftRightPile) {
|
||||
pile1WasChosen = true;
|
||||
} else {
|
||||
pile1WasChosen = chooser.getController().chooseCardsPile(sa, pile1, pile2, sa.getParamOrDefault("FaceDown", "False"));
|
||||
}
|
||||
CardCollectionView chosenPile = pile1WasChosen ? pile1 : pile2;
|
||||
CardCollectionView unchosenPile = !pile1WasChosen ? pile1 : pile2;
|
||||
// first, separate the cards into piles
|
||||
final CardCollectionView pile1;
|
||||
final CardCollection pile2;
|
||||
if (sa.hasParam("DefinedPiles")) {
|
||||
final String[] def = sa.getParam("DefinedPiles").split(",", 2);
|
||||
pile1 = AbilityUtils.getDefinedCards(card, def[0], sa);
|
||||
pile2 = AbilityUtils.getDefinedCards(card, def[1], sa);
|
||||
} else {
|
||||
pile1 = separator.getController().chooseCardsForEffect(pool, sa, title, 0, size, false, null);
|
||||
pile2 = new CardCollection(pool);
|
||||
pile2.removeAll(pile1);
|
||||
}
|
||||
|
||||
StringBuilder notification = new StringBuilder();
|
||||
if (isLeftRightPile) {
|
||||
notification.append("\n");
|
||||
notification.append(Lang.getInstance().getPossessedObject(separator.getName(), Localizer.getInstance().getMessage("lblLeftPile")));
|
||||
notification.append("\n--------------------\n");
|
||||
if (!chosenPile.isEmpty()) {
|
||||
for (Card c : chosenPile) {
|
||||
notification.append(c.getName()).append("\n");
|
||||
}
|
||||
} else {
|
||||
notification.append("(" + Localizer.getInstance().getMessage("lblEmptyPile") + ")\n");
|
||||
if (isLeftRightPile) {
|
||||
pile1WasChosen = true;
|
||||
} else {
|
||||
pile1WasChosen = chooser.getController().chooseCardsPile(sa, pile1, pile2, sa.getParamOrDefault("FaceDown", "False"));
|
||||
}
|
||||
CardCollectionView chosenPile = pile1WasChosen ? pile1 : pile2;
|
||||
CardCollectionView unchosenPile = !pile1WasChosen ? pile1 : pile2;
|
||||
|
||||
StringBuilder notification = new StringBuilder();
|
||||
if (isLeftRightPile) {
|
||||
notification.append("\n");
|
||||
notification.append(Lang.getInstance().getPossessedObject(separator.getName(), Localizer.getInstance().getMessage("lblLeftPile")));
|
||||
notification.append("\n--------------------\n");
|
||||
if (!chosenPile.isEmpty()) {
|
||||
for (Card c : chosenPile) {
|
||||
notification.append(c.getName()).append("\n");
|
||||
}
|
||||
notification.append("\n");
|
||||
notification.append(Lang.getInstance().getPossessedObject(separator.getName(), Localizer.getInstance().getMessage("lblRightPile")));
|
||||
notification.append("\n--------------------\n");
|
||||
if (!unchosenPile.isEmpty()) {
|
||||
for (Card c : unchosenPile) {
|
||||
notification.append(c.getName()).append("\n");
|
||||
}
|
||||
} else {
|
||||
notification.append("(" + Localizer.getInstance().getMessage("lblEmptyPile") + ")\n");
|
||||
}
|
||||
p.getGame().getAction().notifyOfValue(sa, separator, notification.toString(), separator);
|
||||
} else {
|
||||
notification.append(chooser + " " + Localizer.getInstance().getMessage("lblChoosesPile") + " " + (pile1WasChosen ? "1" : "2") + ":\n");
|
||||
if (!chosenPile.isEmpty()) {
|
||||
for (Card c : chosenPile) {
|
||||
notification.append(c.getName()).append("\n");
|
||||
}
|
||||
} else {
|
||||
notification.append("(" + Localizer.getInstance().getMessage("lblEmptyPile") + ")");
|
||||
notification.append("(" + Localizer.getInstance().getMessage("lblEmptyPile") + ")\n");
|
||||
}
|
||||
notification.append("\n");
|
||||
notification.append(Lang.getInstance().getPossessedObject(separator.getName(), Localizer.getInstance().getMessage("lblRightPile")));
|
||||
notification.append("\n--------------------\n");
|
||||
if (!unchosenPile.isEmpty()) {
|
||||
for (Card c : unchosenPile) {
|
||||
notification.append(c.getName()).append("\n");
|
||||
}
|
||||
p.getGame().getAction().notifyOfValue(sa, chooser, notification.toString(), chooser);
|
||||
} else {
|
||||
notification.append("(" + Localizer.getInstance().getMessage("lblEmptyPile") + ")\n");
|
||||
}
|
||||
|
||||
|
||||
if (sa.hasParam("RememberChosen")) {
|
||||
card.addRemembered(chosenPile);
|
||||
}
|
||||
|
||||
// take action on the chosen pile
|
||||
if (sa.hasParam("ChosenPile")) {
|
||||
List<Object> tempRemembered = Lists.newArrayList(card.getRemembered());
|
||||
card.removeRemembered(tempRemembered);
|
||||
card.addRemembered(chosenPile);
|
||||
|
||||
SpellAbility sub = sa.getAdditionalAbility("ChosenPile");
|
||||
if (sub != null) {
|
||||
AbilityUtils.resolve(sub);
|
||||
p.getGame().getAction().notifyOfValue(sa, separator, notification.toString(), separator);
|
||||
} else {
|
||||
notification.append(chooser + " " + Localizer.getInstance().getMessage("lblChoosesPile") + " " + (pile1WasChosen ? "1" : "2") + ":\n");
|
||||
if (!chosenPile.isEmpty()) {
|
||||
for (Card c : chosenPile) {
|
||||
notification.append(c.getName()).append("\n");
|
||||
}
|
||||
card.removeRemembered(chosenPile);
|
||||
card.addRemembered(tempRemembered);
|
||||
} else {
|
||||
notification.append("(" + Localizer.getInstance().getMessage("lblEmptyPile") + ")");
|
||||
}
|
||||
p.getGame().getAction().notifyOfValue(sa, chooser, notification.toString(), chooser);
|
||||
}
|
||||
|
||||
// take action on the unchosen pile
|
||||
if (sa.hasParam("UnchosenPile")) {
|
||||
List<Object> tempRemembered = Lists.newArrayList(card.getRemembered());
|
||||
card.removeRemembered(tempRemembered);
|
||||
card.addRemembered(unchosenPile);
|
||||
|
||||
SpellAbility sub = sa.getAdditionalAbility("UnchosenPile");
|
||||
if (sub != null) {
|
||||
AbilityUtils.resolve(sub);
|
||||
}
|
||||
card.removeRemembered(unchosenPile);
|
||||
card.addRemembered(tempRemembered);
|
||||
if (sa.hasParam("RememberChosen")) {
|
||||
card.addRemembered(chosenPile);
|
||||
}
|
||||
|
||||
// take action on the chosen pile
|
||||
if (sa.hasParam("ChosenPile")) {
|
||||
List<Object> tempRemembered = Lists.newArrayList(card.getRemembered());
|
||||
card.removeRemembered(tempRemembered);
|
||||
card.addRemembered(chosenPile);
|
||||
|
||||
SpellAbility sub = sa.getAdditionalAbility("ChosenPile");
|
||||
if (sub != null) {
|
||||
AbilityUtils.resolve(sub);
|
||||
}
|
||||
card.removeRemembered(chosenPile);
|
||||
card.addRemembered(tempRemembered);
|
||||
}
|
||||
|
||||
// take action on the unchosen pile
|
||||
if (sa.hasParam("UnchosenPile")) {
|
||||
List<Object> tempRemembered = Lists.newArrayList(card.getRemembered());
|
||||
card.removeRemembered(tempRemembered);
|
||||
card.addRemembered(unchosenPile);
|
||||
|
||||
SpellAbility sub = sa.getAdditionalAbility("UnchosenPile");
|
||||
if (sub != null) {
|
||||
AbilityUtils.resolve(sub);
|
||||
}
|
||||
card.removeRemembered(unchosenPile);
|
||||
card.addRemembered(tempRemembered);
|
||||
}
|
||||
}
|
||||
if (!sa.hasParam("KeepRemembered")) {
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
package forge.game.ability.effects;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import forge.game.Game;
|
||||
import forge.game.GameEntity;
|
||||
import forge.game.GameObject;
|
||||
import forge.game.ability.SpellAbilityEffect;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardCollectionView;
|
||||
import forge.game.card.CardLists;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.util.Lang;
|
||||
|
||||
public class UnattachAllEffect extends SpellAbilityEffect {
|
||||
private static void handleUnattachment(final GameEntity o, final Card cardToUnattach) {
|
||||
@@ -121,8 +117,7 @@ public class UnattachAllEffect extends SpellAbilityEffect {
|
||||
protected String getStackDescription(final SpellAbility sa) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append("Unattach all valid Equipment and Auras from ");
|
||||
final List<GameObject> targets = getTargets(sa);
|
||||
sb.append(StringUtils.join(targets, " "));
|
||||
sb.append(Lang.joinHomogenous(getTargets(sa)));
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@@ -130,19 +125,14 @@ public class UnattachAllEffect extends SpellAbilityEffect {
|
||||
public void resolve(final SpellAbility sa) {
|
||||
Card source = sa.getHostCard();
|
||||
final Game game = sa.getActivatingPlayer().getGame();
|
||||
final List<GameObject> targets = getTargets(sa);
|
||||
|
||||
// If Cast Targets will be checked on the Stack
|
||||
for (final Object o : targets) {
|
||||
if (!(o instanceof GameEntity)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (final GameEntity ge : getTargetEntities(sa)) {
|
||||
String valid = sa.getParam("UnattachValid");
|
||||
CardCollectionView unattachList = game.getCardsIn(ZoneType.Battlefield);
|
||||
unattachList = CardLists.getValidCards(unattachList, valid, source.getController(), source, sa);
|
||||
for (final Card c : unattachList) {
|
||||
handleUnattachment((GameEntity) o, c);
|
||||
handleUnattachment(ge, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
package forge.game.ability.effects;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import forge.game.ability.SpellAbilityEffect;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.util.Lang;
|
||||
|
||||
public class UnattachEffect extends SpellAbilityEffect {
|
||||
/* (non-Javadoc)
|
||||
@@ -16,8 +13,7 @@ public class UnattachEffect extends SpellAbilityEffect {
|
||||
protected String getStackDescription(SpellAbility sa) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append("Unattach ");
|
||||
final List<Card> targets = getTargetCards(sa);
|
||||
sb.append(StringUtils.join(targets, " "));
|
||||
sb.append(Lang.joinHomogenous(getTargetCards(sa)));
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@@ -26,15 +22,9 @@ public class UnattachEffect extends SpellAbilityEffect {
|
||||
*/
|
||||
@Override
|
||||
public void resolve(SpellAbility sa) {
|
||||
final List<Card> unattachList = getTargetCards(sa);
|
||||
for (final Card cardToUnattach : unattachList) {
|
||||
if (cardToUnattach.isAura()) {
|
||||
//final boolean gainControl = "GainControl".equals(af.parseParams().get("AILogic"));
|
||||
//AbilityFactoryAttach.handleUnattachAura(cardToUnattach, c, gainControl);
|
||||
} else if (cardToUnattach.isAttachment()) {
|
||||
if (cardToUnattach.isAttachedToEntity()) {
|
||||
cardToUnattach.unattachFromEntity(cardToUnattach.getEntityAttachedTo());
|
||||
}
|
||||
for (final Card cardToUnattach : getTargetCards(sa)) {
|
||||
if (cardToUnattach.isAttachment() && cardToUnattach.isAttachedToEntity()) {
|
||||
cardToUnattach.unattachFromEntity(cardToUnattach.getEntityAttachedTo());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
package forge.game.ability.effects;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import forge.game.ability.SpellAbilityEffect;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardCollection;
|
||||
import forge.game.card.CardCollectionView;
|
||||
import forge.game.card.CardLists;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.AbilitySub;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.zone.ZoneType;
|
||||
@@ -25,17 +21,12 @@ public class UntapAllEffect extends SpellAbilityEffect {
|
||||
public void resolve(SpellAbility sa) {
|
||||
final Card card = sa.getHostCard();
|
||||
CardCollectionView list;
|
||||
List<Player> tgtPlayers = getTargetPlayers(sa);
|
||||
final String valid = sa.getParamOrDefault("ValidCards", "");
|
||||
|
||||
if (!sa.usesTargeting() && !sa.hasParam("Defined")) {
|
||||
list = sa.getActivatingPlayer().getGame().getCardsIn(ZoneType.Battlefield);
|
||||
} else {
|
||||
CardCollection list2 = new CardCollection();
|
||||
for (final Player p : tgtPlayers) {
|
||||
list2.addAll(p.getCardsIn(ZoneType.Battlefield));
|
||||
}
|
||||
list = list2;
|
||||
list = getTargetPlayers(sa).getCardsIn(ZoneType.Battlefield);
|
||||
}
|
||||
list = CardLists.getValidCards(list, valid, sa.getActivatingPlayer(), card, sa);
|
||||
|
||||
|
||||
@@ -48,9 +48,6 @@ public class UntapEffect extends SpellAbilityEffect {
|
||||
if (tgtC.isPhasedOut()) {
|
||||
continue;
|
||||
}
|
||||
if (sa.usesTargeting() && !tgtC.canBeTargetedBy(sa)) {
|
||||
continue;
|
||||
}
|
||||
if (tgtC.isInPlay()) {
|
||||
tgtC.untap(true);
|
||||
}
|
||||
@@ -86,6 +83,10 @@ public class UntapEffect extends SpellAbilityEffect {
|
||||
final String valid = sa.getParam("UntapType");
|
||||
|
||||
for (final Player p : AbilityUtils.getDefinedPlayers(sa.getHostCard(), sa.getParam("Defined"), sa)) {
|
||||
if (!p.isInGame()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
CardCollectionView list = CardLists.getValidCards(p.getGame().getCardsIn(ZoneType.Battlefield),
|
||||
valid, sa.getActivatingPlayer(), sa.getHostCard(), sa);
|
||||
list = CardLists.filter(list, Presets.TAPPED);
|
||||
|
||||
@@ -132,9 +132,10 @@ public class VentureEffect extends SpellAbilityEffect {
|
||||
moveParams.put(AbilityKey.LastStateGraveyard, sa.getLastStateGraveyard());
|
||||
|
||||
for (final Player p : getTargetPlayers(sa)) {
|
||||
if (!sa.usesTargeting() || p.canBeTargetedBy(sa)) {
|
||||
ventureIntoDungeon(sa, p, moveParams);
|
||||
if (!p.isInGame()) {
|
||||
continue;
|
||||
}
|
||||
ventureIntoDungeon(sa, p, moveParams);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -717,8 +717,6 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
if (!turnFaceDown(true) && !isFaceDown()) {
|
||||
return null;
|
||||
}
|
||||
// Move to p's battlefield
|
||||
Game game = p.getGame();
|
||||
|
||||
// Just in case you aren't the controller, now you are!
|
||||
setController(p, game.getNextTimestamp());
|
||||
@@ -726,6 +724,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
// Mark this card as "manifested"
|
||||
setManifested(true);
|
||||
|
||||
// Move to p's battlefield
|
||||
Card c = game.getAction().moveToPlay(this, p, sa, params);
|
||||
if (c.isInPlay()) {
|
||||
c.setManifested(true);
|
||||
@@ -3656,7 +3655,8 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
if (hasKeyword(Keyword.RECONFIGURE)) {
|
||||
// need extra time stamp so it doesn't collide with existing ones
|
||||
long ts = getGame().getNextTimestamp();
|
||||
// TODO make it use a Static Layer Effect instead
|
||||
// 702.151b Attaching an Equipment with reconfigure to another creature causes the Equipment to stop being a creature until it becomes unattached from that creature.
|
||||
// it is not a Static Ability
|
||||
addChangedCardTypes(null, CardType.parse("Creature", true), false, false, false, false, false, false, false, false, ts, 0, true, false);
|
||||
|
||||
GameCommand unattach = new GameCommand() {
|
||||
@@ -6107,7 +6107,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
|
||||
@Override
|
||||
public final boolean canBeTargetedBy(final SpellAbility sa) {
|
||||
if (getOwner().hasLost()) {
|
||||
if (!getOwner().isInGame()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,10 +5,10 @@ PT:1/3
|
||||
K:Reach
|
||||
S:Mode$ Continuous | Affected$ Card.Self | AddKeyword$ Hexproof | IsPresent$ Card.Self+notattacking | Description$ Teleport — CARDNAME has hexproof unless he's attacking.
|
||||
T:Mode$ Attacks | ValidCard$ Creature.YouCtrl+withReach | TriggerZones$ Battlefield | Execute$ TrigUntap | TriggerDescription$ Whenever a creature you control with reach attacks, untap it and it can't be blocked by creatures with greater power this combat.
|
||||
SVar:TrigUntap:DB$ Untap | Defined$ TriggeredAttackerLKICopy | SubAbility$ DBAnimate
|
||||
SVar:DBAnimate:DB$ Animate | Defined$ TriggeredAttackerLKICopy | staticAbilities$ CantBeBlockedPow | Duration$ UntilEndOfCombat
|
||||
SVar:CantBeBlockedPow:Mode$ CantBlockBy | ValidAttacker$ Card.Self | ValidBlocker$ Creature.powerGTX | Description$ CARDNAME can't be blocked by creatures with greater power this combat.
|
||||
SVar:X:Count$CardPower
|
||||
SVar:TrigUntap:DB$ Untap | Defined$ TriggeredAttackerLKICopy | SubAbility$ DBEffect
|
||||
SVar:DBEffect:DB$ Effect | RememberObjects$ TriggeredAttacker | StaticAbilities$ CantBeBlockedPow | ForgetOnMoved$ Battlefield | Duration$ UntilEndOfCombat
|
||||
SVar:CantBeBlockedPow:Mode$ CantBlockBy | ValidAttacker$ Card.IsRemembered | ValidBlocker$ Creature.powerGTX | Description$ CARDNAME can't be blocked by creatures with greater power this combat.
|
||||
SVar:X:Remembered$CardPower
|
||||
T:Mode$ DamageDoneOnce | CombatDamage$ True | ValidSource$ Creature.YouCtrl | TriggerZones$ Battlefield | ValidTarget$ Player | Execute$ TrigDraw | TriggerDescription$ Fierce Punch — Whenever one or more creatures you control deal combat damage to a player, draw a card.
|
||||
SVar:TrigDraw:DB$ Draw
|
||||
DeckHints:Keyword$Reach
|
||||
|
||||
@@ -2,7 +2,6 @@ Name:Fog Patch
|
||||
ManaCost:1 G
|
||||
Types:Instant
|
||||
Text:Cast this spell only during the declare blockers step.
|
||||
A:SP$ RepeatEach | Cost$ 1 G | ActivationPhases$ Declare Blockers | RepeatSubAbility$ DBBecomeBlocked | RepeatCards$ Creature.attacking | SpellDescription$ Attacking creatures become blocked. (This spell works on creatures that can't be blocked.)
|
||||
SVar:DBBecomeBlocked:DB$ BecomesBlocked | Defined$ Remembered
|
||||
A:SP$ BecomesBlocked | Cost$ 1 G | Defined$ Valid Creature.attacking | ActivationPhases$ Declare Blockers | SpellDescription$ Attacking creatures become blocked. (This spell works on creatures that can't be blocked.)
|
||||
AI:RemoveDeck:All
|
||||
Oracle:Cast this spell only during the declare blockers step.\nAttacking creatures become blocked. (This spell works on creatures that can't be blocked.)
|
||||
|
||||
@@ -2,10 +2,8 @@ Name:Mist of Stagnation
|
||||
ManaCost:3 U U
|
||||
Types:Enchantment
|
||||
S:Mode$ Continuous | Affected$ Permanent | AddHiddenKeyword$ CARDNAME doesn't untap during your untap step. | Description$ Permanents don't untap during their controllers' untap steps.
|
||||
T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ Player | Execute$ TrigChoose | TriggerZones$ Battlefield | TriggerDescription$ At the beginning of each player's upkeep, that player chooses a permanent for each card in their graveyard, then untaps those permanents.
|
||||
SVar:TrigChoose:DB$ ChooseCard | Defined$ TriggeredPlayer | Amount$ X | Mandatory$ True | Choices$ Permanent.ActivePlayerCtrl | ChoiceTitle$ Choose a permanent to untap | AILogic$ Untap | SubAbility$ DBUntap
|
||||
SVar:DBUntap:DB$ UntapAll | ValidCards$ Permanent.ChosenCard | SubAbility$ DBCleanup
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearChosenCard$ True
|
||||
T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ Player | Execute$ DBUntap | TriggerZones$ Battlefield | TriggerDescription$ At the beginning of each player's upkeep, that player chooses a permanent for each card in their graveyard, then untaps those permanents.
|
||||
SVar:DBUntap:DB$ Untap | UntapExactly$ True | Defined$ TriggeredPlayer | Amount$ X | UntapType$ Card
|
||||
SVar:X:Count$ValidGraveyard Card.ActivePlayerCtrl
|
||||
AI:RemoveDeck:Random
|
||||
SVar:NonStackingEffect:True
|
||||
|
||||
@@ -4,7 +4,7 @@ Types:Creature Human Knight
|
||||
PT:1/1
|
||||
K:Deathtouch
|
||||
S:Mode$ Continuous | Affected$ Card.Self | AddKeyword$ First Strike | Condition$ PlayerTurn | Description$ As long as it's your turn, CARDNAME has first strike.
|
||||
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ DBVenture | Secondary$ True | TriggerDescription$ Whenever CARDNAME attacks, venture into the dungeon. (Enter the first room or advance to the next room.)
|
||||
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ DBVenture | TriggerDescription$ Whenever CARDNAME attacks, venture into the dungeon. (Enter the first room or advance to the next room.)
|
||||
SVar:DBVenture:DB$ Venture | Defined$ You
|
||||
SVar:HasAttackEffect:TRUE
|
||||
Oracle:Deathtouch\nAs long as it's your turn, Triumphant Adventurer has first strike.\nWhenever Triumphant Adventurer attacks, venture into the dungeon. (Enter the first room or advance to the next room.)
|
||||
|
||||
Reference in New Issue
Block a user