Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Attraction Support #5357

Merged
merged 28 commits into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
174db0c
I think I see why nobody wanted to do this
Jun 2, 2024
1b07896
Merge branch 'master' into Attractions
Jun 2, 2024
b368272
Merge fixes, performance tweaks, updated Unfinity's Editions file
Jun 2, 2024
beed2ad
Merge fixes, performance tweaks, updated Unfinity's Editions file
Jun 2, 2024
c6de232
Merge remote-tracking branch 'origin/Attractions' into Attractions
Jun 2, 2024
8c8c8a7
AttractionsYouVisitedThisTurn and Squirrel Squatters
Jun 8, 2024
279e1e5
Disambiguate requested print names
Jun 8, 2024
49e7576
Merge remote-tracking branch 'origin/master' into Attractions
Jun 8, 2024
a366207
Fix potential NPE.
Jun 8, 2024
1e5e1ba
Redundant import
Jun 8, 2024
614cc96
Support for adding Tabs to TabPageScreen
Jun 9, 2024
239735e
Make countByName work for cards with multiple prints.
Jun 15, 2024
df40cda
Made DeckSection.matchingSection more suitable for general use by shi…
Jun 15, 2024
fbc4759
Support for programmatically setting the advanced search filter for t…
Jun 16, 2024
88c9559
Mobile Deck Editor support for extra sections, including attractions.
Jun 17, 2024
bf1f1ec
Pick-a-Beeble and The Most Dangerous Gamer.
Jun 17, 2024
657ebfd
8 more attractions.
Jun 19, 2024
3e6871c
Merge branch 'master' into Attractions
Jun 20, 2024
85d42bf
Update for "visited this turn" per rules
Jun 23, 2024
6b0d237
Merge branch 'Card-Forge:master' into Attractions
Jetz72 Jun 23, 2024
33c0e5d
Merge branch 'master' into Attractions
Jun 23, 2024
1f77e02
Merge remote-tracking branch 'origin/Attractions' into Attractions
Jun 23, 2024
1233f2b
Remove "Result:" prefix for notification messages with no source.
Jun 23, 2024
f2cefc8
Intervention for AI's gambling problem.
Jun 23, 2024
da34acd
Merge branch 'master' into Attractions
Jun 25, 2024
cfc33fd
Cleanup a couple comments
Jun 25, 2024
611e977
Lifetime Pass Holder and RolledToVisitAttraction trigger condition.
Jul 1, 2024
c346fb0
Remove unused import.
Jul 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 42 additions & 23 deletions forge-core/src/main/java/forge/card/CardDb.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@

import java.util.*;
import java.util.Map.Entry;
import java.util.stream.Collectors;

public final class CardDb implements ICardDatabase, IDeckGenPool {
public final static String foilSuffix = "+";
Expand Down Expand Up @@ -272,7 +273,22 @@ private void addSetCard(CardEdition e, CardInSet cis, CardRules cr) {
}

artIds.put(key, artIdx);
addCard(new PaperCard(cr, e.getCode(), cis.rarity, artIdx, false, cis.collectorNumber, cis.artistName));
addCard(new PaperCard(cr, e.getCode(), cis.rarity, artIdx, false, cis.collectorNumber, cis.artistName, cis.functionalVariantName));
}

private boolean addFromSetByName(String cardName, CardEdition ed, CardRules cr) {
List<CardInSet> cardsInSet = ed.getCardInSet(cardName); // empty collection if not present
if (cr.hasFunctionalVariants()) {
cardsInSet = cardsInSet.stream().filter(c -> StringUtils.isEmpty(c.functionalVariantName)
|| cr.getSupportedFunctionalVariants().contains(c.functionalVariantName)
).collect(Collectors.toList());
}
if (cardsInSet.isEmpty())
return false;
for (CardInSet cis : cardsInSet) {
addSetCard(ed, cis, cr);
}
return true;
}

public void loadCard(String cardName, String setCode, CardRules cr) {
Expand All @@ -285,18 +301,10 @@ public void loadCard(String cardName, String setCode, CardRules cr) {
if (ed == null || ed.equals(CardEdition.UNKNOWN)) {
// look for all possible editions
for (CardEdition e : editions) {
List<CardInSet> cardsInSet = e.getCardInSet(cardName); // empty collection if not present
for (CardInSet cis : cardsInSet) {
addSetCard(e, cis, cr);
reIndexNecessary = true;
}
reIndexNecessary |= addFromSetByName(cardName, e, cr);
}
} else {
List<CardInSet> cardsInSet = ed.getCardInSet(cardName); // empty collection if not present
for (CardInSet cis : cardsInSet) {
addSetCard(ed, cis, cr);
reIndexNecessary = true;
}
reIndexNecessary |= addFromSetByName(cardName, ed, cr);
}

if (reIndexNecessary)
Expand Down Expand Up @@ -324,11 +332,20 @@ public void initialize(boolean logMissingPerEdition, boolean logMissingSummary,

for (CardEdition.CardInSet cis : e.getAllCardsInSet()) {
CardRules cr = rulesByName.get(cis.name);
if (cr != null) {
addSetCard(e, cis, cr);
} else {
if (cr == null) {
missingCards.add(cis.name);
continue;
}
if (cr.hasFunctionalVariants()) {
if (StringUtils.isNotEmpty(cis.functionalVariantName)
&& !cr.getSupportedFunctionalVariants().contains(cis.functionalVariantName)) {
//Supported card, unsupported variant.
//Could note the card as missing but since these are often un-cards,
//it's likely absent because it does something out of scope.
continue;
}
}
addSetCard(e, cis, cr);
}
if (isCoreExpSet && logMissingPerEdition) {
if (missingCards.isEmpty()) {
Expand Down Expand Up @@ -871,14 +888,16 @@ public int getMaxArtIndex(String cardName) {

@Override
public int getArtCount(String cardName, String setCode) {
return getArtCount(cardName, setCode, null);
}
public int getArtCount(String cardName, String setCode, String functionalVariantName) {
if (cardName == null || setCode == null)
return 0;
Collection<PaperCard> cardsInSet = getAllCards(cardName, new Predicate<PaperCard>() {
@Override
public boolean apply(PaperCard card) {
return card.getEdition().equalsIgnoreCase(setCode);
}
});
Predicate<PaperCard> predicate = card -> card.getEdition().equalsIgnoreCase(setCode);
if(functionalVariantName != null && !functionalVariantName.equals(IPaperCard.NO_FUNCTIONAL_VARIANT)) {
predicate = Predicates.and(predicate, card -> functionalVariantName.equals(card.getFunctionalVariant()));
}
Collection<PaperCard> cardsInSet = getAllCards(cardName, predicate);
return cardsInSet.size();
}

Expand Down Expand Up @@ -1142,7 +1161,7 @@ public StringBuilder appendCardToStringBuilder(PaperCard card, StringBuilder sb)
}

if (!hasBadSetInfo) {
int artCount = getArtCount(card.getName(), card.getEdition());
int artCount = getArtCount(card.getName(), card.getEdition(), card.getFunctionalVariant());
sb.append(CardDb.NameSetSeparator).append(card.getEdition());
if (artCount >= IPaperCard.DEFAULT_ART_INDEX) {
sb.append(CardDb.NameSetSeparator).append(card.getArtIndex()); // indexes start at 1 to match image file name conventions
Expand Down Expand Up @@ -1229,7 +1248,7 @@ public CardRules putCard(CardRules rules, List<Pair<String, CardRarity>> whenItW
int artIdx = IPaperCard.DEFAULT_ART_INDEX;
for (CardInSet cis : e.getCardInSet(cardName))
paperCards.add(new PaperCard(rules, e.getCode(), cis.rarity, artIdx++, false,
cis.collectorNumber, cis.artistName));
cis.collectorNumber, cis.artistName, cis.functionalVariantName));
}
} else {
String lastEdition = null;
Expand All @@ -1249,7 +1268,7 @@ public CardRules putCard(CardRules rules, List<Pair<String, CardRarity>> whenItW
int cardInSetIndex = Math.max(artIdx-1, 0); // make sure doesn't go below zero
CardInSet cds = cardsInSet.get(cardInSetIndex); // use ArtIndex to get the right Coll. Number
paperCards.add(new PaperCard(rules, lastEdition, tuple.getValue(), artIdx++, false,
cds.collectorNumber, cds.artistName));
cds.collectorNumber, cds.artistName, cds.functionalVariantName));
}
}
if (paperCards.isEmpty()) {
Expand Down
15 changes: 12 additions & 3 deletions forge-core/src/main/java/forge/card/CardEdition.java
Original file line number Diff line number Diff line change
Expand Up @@ -166,12 +166,14 @@ public static class CardInSet implements Comparable<CardInSet> {
public final String collectorNumber;
public final String name;
public final String artistName;
public final String functionalVariantName;

public CardInSet(final String name, final String collectorNumber, final CardRarity rarity, final String artistName) {
public CardInSet(final String name, final String collectorNumber, final CardRarity rarity, final String artistName, final String functionalVariantName) {
this.name = name;
this.collectorNumber = collectorNumber;
this.rarity = rarity;
this.artistName = artistName;
this.functionalVariantName = functionalVariantName;
}

public String toString() {
Expand All @@ -189,6 +191,10 @@ public String toString() {
sb.append(" @");
sb.append(artistName);
}
if (functionalVariantName != null) {
sb.append(" $");
sb.append(functionalVariantName);
}
return sb.toString();
}

Expand Down Expand Up @@ -567,9 +573,11 @@ protected CardEdition read(File file) {
* cnum - grouping #2
* rarity - grouping #4
* name - grouping #5
* artist name - grouping #7
* functional variant name - grouping #9
*/
// "(^(.?[0-9A-Z]+.?))?(([SCURML]) )?(.*)$"
"(^(.?[0-9A-Z]+\\S?[A-Z]*)\\s)?(([SCURML])\\s)?([^@]*)( @(.*))?$"
"(^(.?[0-9A-Z]+\\S?[A-Z]*)\\s)?(([SCURML])\\s)?([^@\\$]*)( @([^\\$]*))?( \\$(.+))?$"
);

ListMultimap<String, CardInSet> cardMap = ArrayListMultimap.create();
Expand All @@ -595,7 +603,8 @@ protected CardEdition read(File file) {
CardRarity r = CardRarity.smartValueOf(matcher.group(4));
String cardName = matcher.group(5);
String artistName = matcher.group(7);
CardInSet cis = new CardInSet(cardName, collectorNumber, r, artistName);
String functionalVariantName = matcher.group(9);
CardInSet cis = new CardInSet(cardName, collectorNumber, r, artistName, functionalVariantName);

cardMap.put(sectionName, cis);
}
Expand Down
57 changes: 48 additions & 9 deletions forge-core/src/main/java/forge/card/CardFace.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package forge.card;

import forge.card.mana.ManaCost;
import org.apache.commons.lang3.StringUtils;

import java.util.*;
import java.util.Map.Entry;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;

import forge.card.mana.ManaCost;

//
// DO NOT AUTOFORMAT / CHECKSTYLE THIS FILE
Expand Down Expand Up @@ -40,6 +42,7 @@ public enum FaceSelectionMethod { //
private String toughness = null;
private String initialLoyalty = "";
private String defense = "";
private Set<Integer> attractionLights = null;

private String nonAbilityText = null;
private List<String> keywords = null;
Expand All @@ -50,6 +53,8 @@ public enum FaceSelectionMethod { //
private List<String> replacements = null;
private Map<String, String> variables = null;

private Map<String, CardFace> functionalVariants = null;



// these implement ICardCharacteristics
Expand All @@ -60,6 +65,7 @@ public enum FaceSelectionMethod { //
@Override public String getToughness() { return toughness; }
@Override public String getInitialLoyalty() { return initialLoyalty; }
@Override public String getDefense() { return defense; }
@Override public Set<Integer> getAttractionLights() { return attractionLights; }
@Override public String getName() { return this.name; }
@Override public CardType getType() { return this.type; }
@Override public ManaCost getManaCost() { return this.manaCost; }
Expand All @@ -73,24 +79,35 @@ public enum FaceSelectionMethod { //
@Override public Iterable<String> getDraftActions() { return draftActions; }
@Override public Iterable<String> getReplacements() { return replacements; }
@Override public String getNonAbilityText() { return nonAbilityText; }
@Override public Iterable<Entry<String, String>> getVariables() { return variables.entrySet(); }
@Override public Iterable<Entry<String, String>> getVariables() {
if (variables == null)
return null;
return variables.entrySet();
}

@Override public String getAltName() { return this.altName; }
public CardFace(String name0) {

public CardFace(String name0) {
this.name = name0;
if ( StringUtils.isBlank(name0) )
throw new RuntimeException("Card name is empty");
}
// Here come setters to allow parser supply values
void setName(String name) { this.name = name; }
void setName(String name) { this.name = name; }
void setAltName(String name) { this.altName = name; }
void setType(CardType type0) { this.type = type0; }
void setManaCost(ManaCost manaCost0) { this.manaCost = manaCost0; }
void setColor(ColorSet color0) { this.color = color0; }
void setOracleText(String text) { this.oracleText = text; }
void setInitialLoyalty(String value) { this.initialLoyalty = value; }
void setDefense(String value) { this.defense = value; }
void setInitialLoyalty(String value) { this.initialLoyalty = value; }
void setDefense(String value) { this.defense = value; }
void setAttractionLights(String value) {
if (value == null) {
this.attractionLights = null;
return;
}
this.attractionLights = Arrays.stream(value.split(" ")).map(Integer::parseInt).collect(Collectors.toSet());
}

void setPtText(String value) {
final String[] k = value.split("/");
Expand Down Expand Up @@ -127,6 +144,27 @@ static int parsePT(String val) {
void addReplacementEffect(String value) { if (null == this.replacements) { this.replacements = new ArrayList<>(); } this.replacements.add(value);}
void addSVar(String key, String value) { if (null == this.variables) { this.variables = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); } this.variables.put(key, value); }


//Functional variant methods. Used for Attractions and some Un-cards,
//when cards with the same name can have different logic.
public boolean hasFunctionalVariants() {
return this.functionalVariants != null;
}
@Override public ICardFace getFunctionalVariant(String variant) {
if(this.functionalVariants == null)
return null;
return this.functionalVariants.get(variant);
}
CardFace getOrCreateFunctionalVariant(String variant) {
if (this.functionalVariants == null) {
this.functionalVariants = new HashMap<>();
}
if (!this.functionalVariants.containsKey(variant)) {
this.functionalVariants.put(variant, new CardFace(this.name));
}
return this.functionalVariants.get(variant);
}


void assignMissingFields() { // Most scripts do not specify color explicitly
if ( null == oracleText ) { System.err.println(name + " has no Oracle text."); oracleText = ""; }
Expand All @@ -140,6 +178,7 @@ void assignMissingFields() { // Most scripts do not specify color explicitly
if ( replacements == null ) replacements = emptyList;
if ( variables == null ) variables = emptyMap;
if ( null == nonAbilityText ) nonAbilityText = "";
//Not assigning attractionLightVariants here. Too rarely used. Will test for it downstream.
}


Expand Down
Loading
Loading