Skip to content

Commit

Permalink
WHO: caught_in_a_parallel_universe.txt + support (#4093)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
Northmoc authored Mar 6, 2024
1 parent 3b90a74 commit 8c7283d
Show file tree
Hide file tree
Showing 22 changed files with 130 additions and 98 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
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;
Expand Down Expand Up @@ -59,7 +59,7 @@ public void resolve(SpellAbility sa) {
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);

Expand Down Expand Up @@ -100,9 +100,22 @@ public void resolve(SpellAbility sa) {

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,
Expand All @@ -123,16 +136,17 @@ public void resolve(SpellAbility sa) {
}
}
}
} 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);
}
Expand Down Expand Up @@ -168,9 +182,9 @@ public void resolve(SpellAbility sa) {
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");
}
Expand All @@ -180,7 +194,7 @@ public void resolve(SpellAbility sa) {
}
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);
Expand All @@ -189,7 +203,7 @@ public void resolve(SpellAbility sa) {
} 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());
Expand All @@ -200,7 +214,7 @@ public void resolve(SpellAbility sa) {
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);
Expand All @@ -209,17 +223,17 @@ public void resolve(SpellAbility sa) {
} 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") + " ";
Expand Down Expand Up @@ -252,7 +266,7 @@ public void resolve(SpellAbility sa) {
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;
Expand All @@ -263,34 +277,38 @@ public void resolve(SpellAbility sa) {
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));
}
}
if (sa.hasParam("Reveal") && !sa.hasParam("SecretlyChoose")) {
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);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ public void resolve(final SpellAbility sa) {
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();
Expand All @@ -130,6 +131,8 @@ public void resolve(final SpellAbility sa) {
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);
Expand Down Expand Up @@ -223,6 +226,12 @@ public void resolve(final SpellAbility sa) {
}
}
}
} 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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public void resolve(SpellAbility sa) {
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();
Expand All @@ -63,20 +63,31 @@ public void resolve(SpellAbility sa) {
}

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

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);
}
Expand All @@ -97,7 +108,7 @@ public void resolve(SpellAbility sa) {
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);
Expand Down
8 changes: 8 additions & 0 deletions forge-game/src/main/java/forge/game/card/Card.java
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down Expand Up @@ -1162,6 +1163,13 @@ public final void clearImprintedCards() {
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);
}
Expand Down
18 changes: 0 additions & 18 deletions forge-game/src/main/java/forge/game/card/CardProperty.java
Original file line number Diff line number Diff line change
Expand Up @@ -1076,24 +1076,6 @@ public static boolean cardHasProperty(Card card, String property, Player sourceC
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;
Expand Down
2 changes: 1 addition & 1 deletion forge-gui/res/cardsfolder/a/aragorn_company_leader.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ PT:3/3
T:Mode$ RingTemptsYou | ValidCard$ Creature.YouCtrl+Other | TriggerZones$ Battlefield | Execute$ TrigPutCounters | TriggerDescription$ Whenever the Ring tempts you, if you chose a creature other than CARDNAME as your Ring-bearer, put your choice of a counter from among first strike, vigilance, deathtouch, and lifelink on NICKNAME.
SVar:TrigPutCounters:DB$ PutCounter | CounterType$ First Strike,Vigilance,Deathtouch,Lifelink | Defined$ Self
T:Mode$ CounterPlayerAddedAll | ValidObject$ Card.Self+inRealZoneBattlefield | TriggerZones$ Battlefield | ValidSource$ You | Execute$ TrigPutCountersOther | TriggerDescription$ Whenever you put one or more counters on NICKNAME, put one of each of those kinds of counters on up to one other target creature.
SVar:TrigPutCountersOther:DB$ PutCounter | Placer$ TriggeredSource | TriggeredCounterMap$ True | CounterMapValues$ 1 | TargetMin$ 0 | TargetMax$ 1 | TgtPrompt$ Select up to one target other creature | ValidTgts$ Creature.Other
SVar:TrigPutCountersOther:DB$ PutCounter | Placer$ TriggeredSource | TriggeredCounterMap$ True | CounterMapValues$ 1 | TargetMin$ 0 | TargetMax$ 1 | TgtPrompt$ Select up to one other target creature | ValidTgts$ Creature.Other
DeckHas:Ability$Counters
Oracle:Whenever the Ring tempts you, if you chose a creature other than Aragorn, Company Leader as your Ring-bearer, put your choice of a counter from among first strike, vigilance, deathtouch, and lifelink on Aragorn.\nWhenever you put one or more counters on Aragorn, put one of each of those kinds of counters on up to one other target creature.
Loading

0 comments on commit 8c7283d

Please sign in to comment.