WHO: caught_in_a_parallel_universe.txt + support (#4093)

* WHO: caught_in_a_parallel_universe.txt + support

* coward_killer.txt tidy

* human_time_lord_meta_crisis + support

* more tweaks for grenzos_rebuttal and similar
This commit is contained in:
Northmoc
2024-03-06 02:02:22 -05:00
committed by GitHub
parent 3b90a746d3
commit 8c7283d02c
22 changed files with 130 additions and 98 deletions

View File

@@ -3,7 +3,7 @@ package forge.game.ability.effects;
import java.util.*;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import forge.game.Direction;
import forge.game.player.DelayedReveal;
import forge.game.player.PlayerView;
import forge.util.CardTranslation;
@@ -59,7 +59,7 @@ public class ChooseCardEffect extends SpellAbilityEffect {
final Card host = sa.getHostCard();
final Player activator = sa.getActivatingPlayer();
final Game game = activator.getGame();
CardCollection chosen = new CardCollection();
CardCollection allChosen = new CardCollection();
final List<Player> tgtPlayers = getDefinedPlayersOrTargeted(sa);
@@ -100,9 +100,22 @@ public class ChooseCardEffect extends SpellAbilityEffect {
boolean revealTitle = (sa.hasParam("RevealTitle"));
for (Player p : tgtPlayers) {
CardCollectionView pChoices = choices;
CardCollection chosen = new CardCollection();
if (!p.isInGame()) {
p = getNewChooser(sa, activator, p);
}
if (sa.hasParam("ControlledByPlayer")) {
final String param = sa.getParam("ControlledByPlayer");
if (param.equals("Chooser")) {
pChoices = CardLists.filterControlledBy(pChoices, p);
} else if (param.equals("Left") || param.equals("Right")) {
pChoices = CardLists.filterControlledBy(pChoices, game.getNextPlayerAfter(p,
Direction.valueOf(param)));
} else {
pChoices = CardLists.filterControlledBy(pChoices, AbilityUtils.getDefinedPlayers(host, param, sa));
}
}
boolean dontRevealToOwner = true;
if (sa.hasParam("EachBasicType")) {
// Get all lands,
@@ -123,16 +136,17 @@ public class ChooseCardEffect extends SpellAbilityEffect {
}
}
}
} else if (sa.hasParam("ChooseParty")) {
Set<String> partyTypes = Sets.newHashSet("Cleric", "Rogue", "Warrior", "Wizard");
for (final String type : partyTypes) {
CardCollection valids = CardLists.filter(p.getCardsIn(ZoneType.Battlefield),
CardPredicates.isType(type));
valids.removeAll(chosen);
} else if (sa.hasParam("ChooseEach")) {
final String s = sa.getParam("ChooseEach");
final String[] types = s.equals("Party") ? new String[]{"Cleric","Thief","Warrior","Wizard"}
: s.split(" & ");
for (final String type : types) {
CardCollection valids = CardLists.filter(pChoices, CardPredicates.isType(type));
if (!valids.isEmpty()) {
final String prompt = Localizer.getInstance().getMessage("lblChoose") + " " +
Lang.nounWithNumeralExceptOne(1, type);
Card c = p.getController().chooseSingleEntityForEffect(valids, sa, prompt, true, null);
Card c = p.getController().chooseSingleEntityForEffect(valids, sa, prompt,
!sa.hasParam("Mandatory"), null);
if (c != null) {
chosen.add(c);
}
@@ -168,9 +182,9 @@ public class ChooseCardEffect extends SpellAbilityEffect {
CardCollection chosenPool = new CardCollection();
String title = Localizer.getInstance().getMessage("lblChooseCreature");
Card choice = null;
while (!choices.isEmpty() && chosenPool.size() < validAmount) {
while (!pChoices.isEmpty() && chosenPool.size() < validAmount) {
boolean optional = chosenPool.size() >= minAmount;
CardCollection creature = (CardCollection) choices;
CardCollection creature = (CardCollection) pChoices;
if (!chosenPool.isEmpty()) {
title = Localizer.getInstance().getMessage("lblChooseCreatureWithDiffPower");
}
@@ -180,7 +194,7 @@ public class ChooseCardEffect extends SpellAbilityEffect {
}
chosenPool.add(choice);
restrict = restrict + (restrict.contains(".") ? "+powerNE" : ".powerNE") + choice.getNetPower();
choices = CardLists.getValidCards(choices, restrict, activator, host, sa);
pChoices = CardLists.getValidCards(pChoices, restrict, activator, host, sa);
}
if (choice != null) {
chosenPool.add(choice);
@@ -189,7 +203,7 @@ public class ChooseCardEffect extends SpellAbilityEffect {
} else if (sa.hasParam("EachDifferentPower")) {
List<Integer> powers = new ArrayList<>();
CardCollection chosenPool = new CardCollection();
for (Card c : choices) {
for (Card c : pChoices) {
int pow = c.getNetPower();
if (!powers.contains(pow)) {
powers.add(c.getNetPower());
@@ -200,7 +214,7 @@ public class ChooseCardEffect extends SpellAbilityEffect {
re = re + (re.contains(".") ? "+powerEQ" : ".powerEQ");
for (int i : powers) {
String restrict = re + i;
CardCollection valids = CardLists.getValidCards(choices, restrict, activator, host, sa);
CardCollection valids = CardLists.getValidCards(pChoices, restrict, activator, host, sa);
Card choice = p.getController().chooseSingleEntityForEffect(valids, sa,
Localizer.getInstance().getMessage("lblChooseCreatureWithXPower", i), false, null);
chosenPool.add(choice);
@@ -209,17 +223,17 @@ public class ChooseCardEffect extends SpellAbilityEffect {
} else if (sa.hasParam("ControlAndNot")) {
String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChooseCreature");
// Targeted player (p) chooses N creatures that belongs to them
CardCollection tgtPlayerCtrl = CardLists.filterControlledBy(choices, p);
CardCollection tgtPlayerCtrl = CardLists.filterControlledBy(pChoices, p);
chosen.addAll(p.getController().chooseCardsForEffect(tgtPlayerCtrl, sa, title + " " + "you control", minAmount, validAmount,
!sa.hasParam("Mandatory"), null));
// Targeted player (p) chooses N creatures that don't belong to them
CardCollection notTgtPlayerCtrl = new CardCollection(choices);
CardCollection notTgtPlayerCtrl = new CardCollection(pChoices);
notTgtPlayerCtrl.removeAll(tgtPlayerCtrl);
chosen.addAll(p.getController().chooseCardsForEffect(notTgtPlayerCtrl, sa, title + " " + "you don't control", minAmount, validAmount,
!sa.hasParam("Mandatory"), null));
} else if (sa.hasParam("AtRandom") && !choices.isEmpty()) {
} else if (sa.hasParam("AtRandom") && !pChoices.isEmpty()) {
// don't pass FCollection for direct modification, the Set part would get messed up
chosen = new CardCollection(Aggregates.random(choices, validAmount));
chosen = new CardCollection(Aggregates.random(pChoices, validAmount));
dontRevealToOwner = false;
} else {
String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChooseaCard") + " ";
@@ -252,7 +266,7 @@ public class ChooseCardEffect extends SpellAbilityEffect {
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,
Card choice = p.getController().chooseSingleEntityForEffect(pChoices, delayedReveal, sa, title,
!sa.hasParam("Mandatory"), p, null);
if (choice == null) {
return;
@@ -263,7 +277,7 @@ public class ChooseCardEffect extends SpellAbilityEffect {
p.removeController(controlTimestamp);
}
} else {
chosen.addAll(p.getController().chooseCardsForEffect(choices, sa, title, minAmount, validAmount,
chosen.addAll(p.getController().chooseCardsForEffect(pChoices, sa, title, minAmount, validAmount,
!sa.hasParam("Mandatory"), null));
}
}
@@ -271,26 +285,30 @@ public class ChooseCardEffect extends SpellAbilityEffect {
game.getAction().reveal(chosen, p, dontRevealToOwner, revealTitle ? sa.getParam("RevealTitle") :
Localizer.getInstance().getMessage("lblChosenCards") + " ", !revealTitle);
}
if (sa.hasParam("ChosenMap")) {
host.addToChosenMap(p, chosen);
}
allChosen.addAll(chosen);
}
if (sa.hasParam("Reveal") && sa.hasParam("SecretlyChoose")) {
for (final Player p : tgtPlayers) {
game.getAction().reveal(chosen, p, true, revealTitle ?
game.getAction().reveal(allChosen, p, true, revealTitle ?
sa.getParam("RevealTitle") : Localizer.getInstance().getMessage("lblChosenCards") + " ",
!revealTitle);
}
}
host.setChosenCards(chosen);
host.setChosenCards(allChosen);
if (sa.hasParam("ForgetOtherRemembered")) {
host.clearRemembered();
}
if (sa.hasParam("RememberChosen")) {
host.addRemembered(chosen);
host.addRemembered(allChosen);
}
if (sa.hasParam("ForgetChosen")) {
host.removeRemembered(chosen);
host.removeRemembered(allChosen);
}
if (sa.hasParam("ImprintChosen")) {
host.addImprintedCards(chosen);
host.addImprintedCards(allChosen);
}
}
}

View File

@@ -106,6 +106,7 @@ public class CopyPermanentEffect extends TokenEffectBase {
final Player activator = sa.getActivatingPlayer();
final Game game = host.getGame();
boolean useZoneTable = true;
boolean chosenMap = "ChosenMap".equals(sa.getParam("Defined"));
CardZoneTable triggerList = sa.getChangeZoneTable();
if (triggerList == null) {
triggerList = new CardZoneTable();
@@ -130,6 +131,8 @@ public class CopyPermanentEffect extends TokenEffectBase {
List<Player> controllers = Lists.newArrayList();
if (sa.hasParam("Controller")) {
controllers = AbilityUtils.getDefinedPlayers(host, sa.getParam("Controller"), sa);
} else if (chosenMap) {
controllers.addAll(host.getChosenMap().keySet());
}
if (controllers.isEmpty()) {
controllers.add(activator);
@@ -223,6 +226,12 @@ public class CopyPermanentEffect extends TokenEffectBase {
}
}
}
} else if (chosenMap) {
if (sa.hasParam("ChosenMapIndex")) {
final int index = Integer.valueOf(sa.getParam("ChosenMapIndex"));
if (index >= host.getChosenMap().get(controller).size()) continue;
tgtCards.add(host.getChosenMap().get(controller).get(index));
} else tgtCards = host.getChosenMap().get(controller);
} else {
tgtCards = getDefinedCardsOrTargeted(sa);
}

View File

@@ -45,7 +45,7 @@ public class CountersPutAllEffect extends SpellAbilityEffect {
final Card host = sa.getHostCard();
final Player activator = sa.getActivatingPlayer();
final CounterType type = CounterType.getType(sa.getParam("CounterType"));
final int counterAmount = AbilityUtils.calculateAmount(host, sa.getParamOrDefault("CounterNum", "1"), sa);
int counterAmount = AbilityUtils.calculateAmount(host, sa.getParamOrDefault("CounterNum", "1"), sa);
final String valid = sa.getParam("ValidCards");
final ZoneType zone = sa.hasParam("ValidZone") ? ZoneType.smartValueOf(sa.getParam("ValidZone")) : ZoneType.Battlefield;
final Game game = activator.getGame();
@@ -63,11 +63,13 @@ public class CountersPutAllEffect extends SpellAbilityEffect {
}
Player placer = activator;
boolean placerPerCard = false;
String placerPerCard = "";
if (sa.hasParam("Placer")) {
final String pstr = sa.getParam("Placer");
if (pstr.contains("Controller")) {
placerPerCard = true;
if (pstr.equals("Controller")) {
placerPerCard = "Controller";
} else if (pstr.equals("Owner")) {
placerPerCard = "Owner";
} else {
placer = AbilityUtils.getDefinedPlayers(host, pstr, sa).get(0);
}
@@ -75,8 +77,17 @@ public class CountersPutAllEffect extends SpellAbilityEffect {
GameEntityCounterTable table = new GameEntityCounterTable();
for (final Card tgtCard : cards) {
if (placerPerCard) {
if (placerPerCard.equals("Controller")) {
placer = tgtCard.getController();
} else if (placerPerCard.equals("Owner")) {
placer = tgtCard.getOwner();
}
if (sa.hasParam("AmountByChosenMap")) {
final String[] parse = sa.getParam("AmountByChosenMap").split(" INDEX ");
final int index = parse.length > 1 ? Integer.valueOf(parse[1]) : 0;
if (index >= host.getChosenMap().get(placer).size()) continue;
final Card chosen = host.getChosenMap().get(placer).get(index);
counterAmount = AbilityUtils.xCount(chosen, parse[0], sa);
}
tgtCard.addCounter(type, counterAmount, placer, table);
}
@@ -97,7 +108,7 @@ public class CountersPutAllEffect extends SpellAbilityEffect {
AbilityUtils.calculateAmount(host, sa.getParam("CounterNum2"), sa) : counterAmount;
for (final Card tgtCard : cards) {
if (placerPerCard) {
if (placerPerCard.equals("Controller")) {
placer = tgtCard.getController();
}
tgtCard.addCounter(type2, counterAmount2, placer, table);

View File

@@ -113,6 +113,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
private Map<Long, CardCollection> mustBlockCards = Maps.newHashMap();
private List<Card> blockedThisTurn = Lists.newArrayList();
private List<Card> blockedByThisTurn = Lists.newArrayList();
private Map<Player, CardCollection> chosenMap = Maps.newHashMap();
private CardCollection untilLeavesBattlefield = new CardCollection();
@@ -1162,6 +1163,13 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
imprintedCards = view.clearCards(imprintedCards, TrackableProperty.ImprintedCards);
}
public final void addToChosenMap(final Player p, final CardCollection chosen) {
chosenMap.put(p, chosen);
}
public final Map<Player, CardCollection> getChosenMap() {
return chosenMap;
}
public final CardCollectionView getExiledCards() {
return CardCollection.getView(exiledCards);
}

View File

@@ -1076,24 +1076,6 @@ public class CardProperty {
if (!card.wasMilled()) {
return false;
}
} else if (property.startsWith("ControlledByPlayerInTheDirection")) {
final String restrictions = property.split("ControlledByPlayerInTheDirection_")[1];
final String[] res = restrictions.split("_");
final Direction direction = Direction.valueOf(res[0]);
Player p = null;
if (res.length > 1) {
for (Player pl : game.getPlayers()) {
if (pl.isValid(res[1], sourceController, source, spellAbility)) {
p = pl;
break;
}
}
} else {
p = sourceController;
}
if (p == null || !controller.equals(game.getNextPlayerAfter(p, direction))) {
return false;
}
} else if (property.equals("hasABasicLandType")) {
if (!card.hasABasicLandType()) {
return false;