mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-15 18:28:00 +00:00
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:
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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":
|
||||||
|
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());
|
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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
@@ -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
|
||||||
7
forge-gui/res/tokenscripts/volos_journal.txt
Normal file
7
forge-gui/res/tokenscripts/volos_journal.txt
Normal 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.
|
||||||
@@ -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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user