The bigger looking ones from more indentation

This commit is contained in:
tool4EvEr
2022-11-25 21:28:59 +01:00
parent 0146e0c72e
commit 9fabf6086c
20 changed files with 912 additions and 941 deletions

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}
}

View File

@@ -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) {

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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");

View File

@@ -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;

View File

@@ -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;
}
}
}

View File

@@ -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
}
}

View File

@@ -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());

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}

View File

@@ -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()) {

View File

@@ -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

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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;
}
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;
}
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");
}
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");
}
// 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);
}
// 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);
}
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");
}
} 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")) {