CLB: Volo, Journal, support, etc. (#1211)

* volo_itinerant_scholar.txt

* volos_journal.txt

* TrackableProperty.NotedTypes

* ChooseTypeEffect.resolve implement "TypesFromDefined"

* ChooseTypeEffect.resolve implement "Note"

* CardView.getNotedTypes / CardView.updateNotedTypes

* CardDetailUtil.composeCardText add noted type area

* Card.java implement notedTypes

* AbilityUtils.xCount "CardNumNotedTypes"
This commit is contained in:
Northmoc
2022-08-04 11:49:09 -04:00
committed by GitHub
parent 7870b27734
commit fff9968b5b
8 changed files with 89 additions and 8 deletions

View File

@@ -12,16 +12,12 @@ import java.util.Map.Entry;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import com.google.common.collect.*;
import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import forge.card.CardStateName; import forge.card.CardStateName;
import forge.card.CardType; import forge.card.CardType;
@@ -2046,6 +2042,10 @@ public class AbilityUtils {
return doXMath(ce == null ? 0 : getNumberOfTypes(ce), expr, c, ctb); return doXMath(ce == null ? 0 : getNumberOfTypes(ce), expr, c, ctb);
} }
if (sq[0].contains("CardNumNotedTypes")) {
return doXMath(c.getNumNotedTypes(), expr, c, ctb);
}
if (sq[0].contains("CardNumColors")) { if (sq[0].contains("CardNumColors")) {
return doXMath(c.getColor().countColors(), expr, c, ctb); return doXMath(c.getColor().countColors(), expr, c, ctb);
} }

View File

@@ -6,6 +6,7 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
import forge.card.CardType; import forge.card.CardType;
import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect; import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.player.Player; import forge.game.player.Player;
@@ -49,7 +50,17 @@ public class ChooseTypeEffect extends SpellAbilityEffect {
validTypes.addAll(CardType.getAllCardTypes()); validTypes.addAll(CardType.getAllCardTypes());
break; break;
case "Creature": case "Creature":
validTypes.addAll(CardType.getAllCreatureTypes()); if (sa.hasParam("TypesFromDefined")) {
for (final Card c : AbilityUtils.getDefinedCards(card, sa.getParam("TypesFromDefined"), sa)) {
for (String t : c.getType()) {
if (CardType.isACreatureType(t)) {
validTypes.add(t);
}
}
}
} else {
validTypes.addAll(CardType.getAllCreatureTypes());
}
break; break;
case "Basic Land": case "Basic Land":
validTypes.addAll(CardType.getBasicTypes()); validTypes.addAll(CardType.getBasicTypes());
@@ -75,10 +86,17 @@ public class ChooseTypeEffect extends SpellAbilityEffect {
for (final String s : invalidTypes) { for (final String s : invalidTypes) {
validTypes.remove(s); validTypes.remove(s);
} }
if (sa.hasParam("Note") && card.hasAnyNotedType()) {
for (String noted : card.getNotedTypes()) {
validTypes.remove(noted);
}
}
final TargetRestrictions tgt = sa.getTargetRestrictions(); final TargetRestrictions tgt = sa.getTargetRestrictions();
if (!validTypes.isEmpty()) { 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) { for (final Player p : tgtPlayers) {
String choice; String choice;
if ((tgt == null) || p.canBeTargetedBy(sa)) { if ((tgt == null) || p.canBeTargetedBy(sa)) {
@@ -89,7 +107,9 @@ public class ChooseTypeEffect extends SpellAbilityEffect {
} else { } else {
choice = p.getController().chooseSomeType(type, sa, validTypes, invalidTypes); choice = p.getController().chooseSomeType(type, sa, validTypes, invalidTypes);
} }
if (!sa.hasParam("ChooseType2")) { if (sa.hasParam("Note")) {
card.addNotedType(choice);
} else if (!sa.hasParam("ChooseType2")) {
card.setChosenType(choice); card.setChosenType(choice);
} else { } else {
card.setChosenType2(choice); card.setChosenType2(choice);

View File

@@ -276,6 +276,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
private String originalText = "", text = ""; private String originalText = "", text = "";
private String chosenType = ""; private String chosenType = "";
private String chosenType2 = ""; private String chosenType2 = "";
private List<String> notedTypes = new ArrayList<>();
private List<String> chosenColors; private List<String> chosenColors;
private String chosenName = ""; private String chosenName = "";
private String chosenName2 = ""; private String chosenName2 = "";
@@ -1745,6 +1746,29 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
return chosenType2 != null && !chosenType2.isEmpty(); return chosenType2 != null && !chosenType2.isEmpty();
} }
public final boolean hasAnyNotedType() {
return notedTypes != null && !notedTypes.isEmpty();
}
public final void addNotedType(final String type) {
notedTypes.add(type);
view.updateNotedTypes(this);
}
public final Iterable<String> getNotedTypes() {
if (notedTypes == null) {
return Lists.newArrayList();
}
return notedTypes;
}
public final int getNumNotedTypes() {
if (notedTypes == null) {
return 0;
}
return notedTypes.size();
}
public final String getChosenColor() { public final String getChosenColor() {
if (hasChosenColor()) { if (hasChosenColor()) {
return chosenColors.get(0); return chosenColors.get(0);

View File

@@ -359,6 +359,13 @@ public class CardView extends GameEntityView {
set(TrackableProperty.ChosenType2, c.getChosenType2()); set(TrackableProperty.ChosenType2, c.getChosenType2());
} }
public List<String> getNotedTypes() {
return get(TrackableProperty.NotedTypes);
}
void updateNotedTypes(Card c) {
set(TrackableProperty.NotedTypes, c.getNotedTypes());
}
public String getChosenNumber() { public String getChosenNumber() {
return get(TrackableProperty.ChosenNumber); return get(TrackableProperty.ChosenNumber);
} }

View File

@@ -59,6 +59,7 @@ public enum TrackableProperty {
ShieldCount(TrackableTypes.IntegerType), ShieldCount(TrackableTypes.IntegerType),
ChosenType(TrackableTypes.StringType), ChosenType(TrackableTypes.StringType),
ChosenType2(TrackableTypes.StringType), ChosenType2(TrackableTypes.StringType),
NotedTypes(TrackableTypes.StringListType),
ChosenColors(TrackableTypes.StringListType), ChosenColors(TrackableTypes.StringListType),
ChosenCards(TrackableTypes.CardViewCollectionType), ChosenCards(TrackableTypes.CardViewCollectionType),
ChosenNumber(TrackableTypes.StringType), ChosenNumber(TrackableTypes.StringType),

View File

@@ -0,0 +1,12 @@
Name:Volo, Itinerant Scholar
ManaCost:2 U
Types:Legendary Creature Human Wizard
PT:2/3
T:Mode$ ChangesZone | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigToken | TriggerDescription$ When NICKNAME enters the battlefield, create Volo's Journal, a legendary colorless artifact token with hexproof and "Whenever you cast a creature spell, note one of its creature types that hasn't been noted for this artifact."
SVar:TrigToken:DB$ Token | TokenScript$ volos_journal
A:AB$ Pump | Cost$ 2 T | ValidTgts$ Permanent.namedVolo's Journal+YouCtrl | TgtPrompt$ Select target permanent you control named Volo's Journal | SubAbility$ DBDraw | StackDescription$ None | SpellDescription$ Draw a card for each creature type noted for target permanent you control named Volo's Journal.
SVar:DBDraw:DB$ Draw | NumCards$ X
SVar:X:Targeted$CardNumNotedTypes
K:Choose a Background
DeckHas:Ability$Token & Type$Artifact
Oracle:When Volo enters the battlefield, create Volo's Journal, a legendary colorless artifact token with hexproof and "Whenever you cast a creature spell, note one of its creature types that hasn't been noted for this artifact."\n{2}, {T}: Draw a card for each creature type noted for target permanent you control named Volo's Journal.\nChoose a Background

View File

@@ -0,0 +1,7 @@
Name:Volo's Journal
ManaCost:no cost
Types:Legendary Artifact
K:Hexproof
T:Mode$ SpellCast | ValidCard$ Creature | ValidActivatingPlayer$ You | Execute$ TrigNoteType | TriggerZones$ Battlefield | TriggerDescription$ Whenever you cast a creature spell, note one of its creature types that hasn't been noted for this artifact.
SVar:TrigNoteType:DB$ ChooseType | Type$ Creature | TypesFromDefined$ TriggeredCard | Note$ True
Oracle:Hexproof\nWhenever you cast a creature spell, note one of its creature types that hasn't been noted for this artifact.

View File

@@ -419,6 +419,16 @@ public class CardDetailUtil {
area.append(")"); area.append(")");
} }
// noted types
if (card.getNotedTypes() != null && !card.getNotedTypes().isEmpty()) {
if (area.length() != 0) {
area.append("\n");
}
area.append("(noted type").append(card.getNotedTypes().size() == 1 ? ": " : "s: ");
area.append(Lang.joinHomogenous(card.getNotedTypes()));
area.append(")");
}
// chosen color // chosen color
if (card.getChosenColors() != null && !card.getChosenColors().isEmpty()) { if (card.getChosenColors() != null && !card.getChosenColors().isEmpty()) {
if (area.length() != 0) { if (area.length() != 0) {