foul-magics/Mage/src/main/java/mage/cards/repository/CardInfo.java
Oleg Agafonov 76e57d009e Multiple changes:
- game: fixed possible empty pay text in custom costs;
- debug: improved debug info for CardInfo objects;
- db: removed unused split sides from cards database;
- db: fixed constant cards adding on each cards database scan (e.g. on tests start);
2021-08-13 14:54:10 +04:00

486 lines
15 KiB
Java

package mage.cards.repository;
import com.j256.ormlite.field.DataType;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import mage.ObjectColor;
import mage.abilities.Ability;
import mage.abilities.SpellAbility;
import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility;
import mage.cards.*;
import mage.cards.mock.MockCard;
import mage.cards.mock.MockSplitCard;
import mage.constants.*;
import mage.util.CardUtil;
import mage.util.SubTypes;
import org.apache.log4j.Logger;
import java.util.*;
import java.util.stream.Collectors;
/**
* Auto-generated table on each release, so no need SQL-updates on structure changes.
*
* @author North
*/
@DatabaseTable(tableName = "card")
public class CardInfo {
private static final int MAX_RULE_LENGTH = 750;
private static final String SEPARATOR = "@@@";
public static final String SPLIT_MANA_SEPARATOR_SHORT = "*";
public static final String SPLIT_MANA_SEPARATOR_FULL = "{" + SPLIT_MANA_SEPARATOR_SHORT + "}";
public static final String SPLIT_MANA_SEPARATOR_RENDER = " / ";
@DatabaseField(indexName = "name_index")
protected String name;
/**
* lower_name exists to speed up importing decks, specifically to provide an indexed column.
* H2 does not support expressions in indices, so we need a physical column.
*/
@DatabaseField(indexName = "lower_name_index")
protected String lower_name;
@DatabaseField(indexName = "setCode_cardNumber_index")
protected String setCode;
@DatabaseField(indexName = "setCode_cardNumber_index")
protected String cardNumber;
@DatabaseField(indexName = "className_index")
protected String className;
@DatabaseField
protected String power;
@DatabaseField
protected String toughness;
@DatabaseField
protected String startingLoyalty;
@DatabaseField
protected int manaValue;
@DatabaseField(dataType = DataType.ENUM_STRING)
protected Rarity rarity;
@DatabaseField
protected String types;
@DatabaseField
protected String subtypes;
@DatabaseField
protected String supertypes;
@DatabaseField
protected String manaCosts;
@DatabaseField(dataType = DataType.STRING, width = MAX_RULE_LENGTH)
protected String rules;
@DatabaseField
protected boolean black;
@DatabaseField
protected boolean blue;
@DatabaseField
protected boolean green;
@DatabaseField
protected boolean red;
@DatabaseField
protected boolean white;
@DatabaseField
protected String frameColor;
@DatabaseField
protected String frameStyle;
@DatabaseField
protected boolean variousArt;
@DatabaseField
protected boolean splitCard;
@DatabaseField
protected boolean splitCardFuse;
@DatabaseField
protected boolean splitCardAftermath;
@DatabaseField
protected boolean splitCardHalf;
@DatabaseField
protected boolean flipCard;
@DatabaseField
protected boolean doubleFaced;
@DatabaseField(indexName = "name_index")
protected boolean nightCard;
@DatabaseField
protected String flipCardName;
@DatabaseField
protected String secondSideName;
@DatabaseField
protected boolean adventureCard;
@DatabaseField
protected String adventureSpellName;
@DatabaseField
protected boolean modalDoubleFacesCard;
@DatabaseField
protected String modalDoubleFacesSecondSideName;
// if you add new field with card side name then update CardRepository.addNewNames too
public enum ManaCostSide {
LEFT, RIGHT, ALL
}
public CardInfo() {
}
public CardInfo(Card card) {
this.name = card.getName();
this.lower_name = name.toLowerCase(Locale.ENGLISH);
this.cardNumber = card.getCardNumber();
this.setCode = card.getExpansionSetCode();
this.className = card.getClass().getCanonicalName();
this.power = card.getPower().toString();
this.toughness = card.getToughness().toString();
this.manaValue = card.getManaValue();
this.rarity = card.getRarity();
this.splitCard = card instanceof SplitCard;
this.splitCardFuse = card.getSpellAbility() != null && card.getSpellAbility().getSpellAbilityType() == SpellAbilityType.SPLIT_FUSED;
this.splitCardAftermath = card.getSpellAbility() != null && card.getSpellAbility().getSpellAbilityType() == SpellAbilityType.SPLIT_AFTERMATH;
this.flipCard = card.isFlipCard();
this.flipCardName = card.getFlipCardName();
this.doubleFaced = card.isTransformable() && card.getSecondCardFace() != null;
this.nightCard = card.isNightCard();
Card secondSide = card.getSecondCardFace();
if (secondSide != null) {
this.secondSideName = secondSide.getName();
}
if (card instanceof AdventureCard) {
this.adventureCard = true;
this.adventureSpellName = ((AdventureCard) card).getSpellCard().getName();
}
if (card instanceof ModalDoubleFacesCard) {
this.modalDoubleFacesCard = true;
this.modalDoubleFacesSecondSideName = ((ModalDoubleFacesCard) card).getRightHalfCard().getName();
}
this.frameStyle = card.getFrameStyle().toString();
this.frameColor = card.getFrameColor(null).toString();
this.variousArt = card.getUsesVariousArt();
this.blue = card.getColor(null).isBlue();
this.black = card.getColor(null).isBlack();
this.green = card.getColor(null).isGreen();
this.red = card.getColor(null).isRed();
this.white = card.getColor(null).isWhite();
this.setTypes(card.getCardType());
this.setSubtypes(card.getSubtype().stream().map(SubType::toString).collect(Collectors.toList()));
this.setSuperTypes(card.getSuperType());
// mana cost can contains multiple cards (split left/right, modal double faces, card/adventure)
if (card instanceof SplitCard) {
List<String> manaCostLeft = ((SplitCard) card).getLeftHalfCard().getManaCostSymbols();
List<String> manaCostRight = ((SplitCard) card).getRightHalfCard().getManaCostSymbols();
this.setManaCosts(CardUtil.concatManaSymbols(SPLIT_MANA_SEPARATOR_FULL, manaCostLeft, manaCostRight));
} else if (card instanceof ModalDoubleFacesCard) {
List<String> manaCostLeft = ((ModalDoubleFacesCard) card).getLeftHalfCard().getManaCostSymbols();
List<String> manaCostRight = ((ModalDoubleFacesCard) card).getRightHalfCard().getManaCostSymbols();
this.setManaCosts(CardUtil.concatManaSymbols(SPLIT_MANA_SEPARATOR_FULL, manaCostLeft, manaCostRight));
} else if (card instanceof AdventureCard) {
List<String> manaCostLeft = ((AdventureCard) card).getSpellCard().getManaCostSymbols();
List<String> manaCostRight = card.getManaCostSymbols();
this.setManaCosts(CardUtil.concatManaSymbols(SPLIT_MANA_SEPARATOR_FULL, manaCostLeft, manaCostRight));
} else {
this.setManaCosts(card.getManaCostSymbols());
}
int length = 0;
List<String> rulesList = new ArrayList<>();
if (card instanceof SplitCard) {
for (String rule : ((SplitCard) card).getLeftHalfCard().getRules()) {
length += rule.length();
rulesList.add(rule);
}
for (String rule : ((SplitCard) card).getRightHalfCard().getRules()) {
length += rule.length();
rulesList.add(rule);
}
for (String rule : card.getRules()) {
length += rule.length();
rulesList.add(rule);
}
} else if (card instanceof ModalDoubleFacesCard) {
// mdf card return main side's rules only (GUI can toggle it to another side)
for (String rule : card.getRules()) {
length += rule.length();
rulesList.add(rule);
}
} else {
for (String rule : card.getRules()) {
length += rule.length();
rulesList.add(rule);
}
}
if (length > MAX_RULE_LENGTH) {
length = 0;
List<String> shortRules = new ArrayList<>();
for (String rule : rulesList) {
if (length + rule.length() + 3 <= MAX_RULE_LENGTH) {
shortRules.add(rule);
length += rule.length() + 3;
} else {
shortRules.add(rule.substring(0, MAX_RULE_LENGTH - (length + 3)));
break;
}
}
Logger.getLogger(CardInfo.class).warn("Card rule text was cut - cardname: " + card.getName());
this.setRules(shortRules);
} else {
this.setRules(rulesList);
}
SpellAbility spellAbility = card.getSpellAbility();
if (spellAbility != null) {
SpellAbilityType spellAbilityType = spellAbility.getSpellAbilityType();
if (spellAbilityType == SpellAbilityType.SPLIT_LEFT || spellAbilityType == SpellAbilityType.SPLIT_RIGHT) {
this.className = this.setCode + '.' + this.name;
this.splitCardHalf = true;
}
}
// Starting loyalty
if (card.isPlaneswalker()) {
for (Ability ab : card.getAbilities()) {
if (ab instanceof PlaneswalkerEntersWithLoyaltyCountersAbility) {
this.startingLoyalty = "" + ((PlaneswalkerEntersWithLoyaltyCountersAbility) ab).getStartingLoyalty();
}
}
if (this.startingLoyalty == null) {
this.startingLoyalty = "";
}
} else {
this.startingLoyalty = "";
}
}
public Card getCard() {
return CardImpl.createCard(className, new CardSetInfo(name, setCode, cardNumber, rarity, new CardGraphicInfo(FrameStyle.valueOf(frameStyle), variousArt)));
}
public Card getMockCard() {
if (this.splitCard) {
return new MockSplitCard(this);
} else {
return new MockCard(this);
}
}
public boolean usesVariousArt() {
return variousArt;
}
public ObjectColor getColor() {
ObjectColor color = new ObjectColor();
color.setBlack(black);
color.setBlue(blue);
color.setGreen(green);
color.setRed(red);
color.setWhite(white);
return color;
}
public ObjectColor getFrameColor() {
return new ObjectColor(frameColor);
}
public FrameStyle getFrameStyle() {
return FrameStyle.valueOf(this.frameStyle);
}
private String joinList(List<String> items) {
StringBuilder sb = new StringBuilder();
for (Object item : items) {
sb.append(item.toString()).append(SEPARATOR);
}
return sb.toString();
}
public static List<String> parseList(String list, ManaCostSide manaCostSide) {
if (list.isEmpty()) {
return Collections.emptyList();
}
List<String> res = new ArrayList<>();
boolean leftSide = true;
for (String s : list.split(SEPARATOR)) {
if (s.equals(SPLIT_MANA_SEPARATOR_FULL)) {
leftSide = false;
continue;
}
if (manaCostSide.equals(ManaCostSide.ALL)
|| (manaCostSide.equals(ManaCostSide.LEFT) && leftSide)
|| (manaCostSide.equals(ManaCostSide.RIGHT) && !leftSide)) {
res.add(s);
}
}
return res;
}
public final List<CardType> getTypes() {
List<CardType> list = new ArrayList<>();
for (String type : this.types.split(SEPARATOR)) {
try {
list.add(CardType.valueOf(type));
} catch (IllegalArgumentException e) {
}
}
return list;
}
public final void setTypes(List<CardType> types) {
StringBuilder sb = new StringBuilder();
for (CardType item : types) {
sb.append(item.name()).append(SEPARATOR);
}
this.types = sb.toString();
}
public int getManaValue() {
return manaValue;
}
public final List<String> getManaCosts(ManaCostSide manaCostSide) {
return parseList(manaCosts, manaCostSide);
}
public final void setManaCosts(List<String> manaCosts) {
this.manaCosts = joinList(manaCosts);
}
public String getName() {
return name;
}
public String getPower() {
return power;
}
public Rarity getRarity() {
return rarity;
}
public final List<String> getRules() {
return parseList(rules, ManaCostSide.ALL);
}
public final void setRules(List<String> rules) {
this.rules = joinList(rules);
}
public final SubTypes getSubTypes() {
SubTypes sl = new SubTypes();
if (subtypes.trim().isEmpty()) {
return sl;
}
for (String s : subtypes.split(SEPARATOR)) {
sl.add(SubType.fromString(s));
}
return sl;
}
public final void setSubtypes(List<String> subtypes) {
this.subtypes = joinList(subtypes);
}
public final Set<SuperType> getSupertypes() {
Set<SuperType> list = EnumSet.noneOf(SuperType.class);
for (String type : this.supertypes.split(SEPARATOR)) {
try {
list.add(SuperType.valueOf(type));
} catch (IllegalArgumentException e) {
}
}
return list;
}
public final void setSuperTypes(Set<SuperType> superTypes) {
StringBuilder sb = new StringBuilder();
for (SuperType item : superTypes) {
sb.append(item.name()).append(SEPARATOR);
}
this.supertypes = sb.toString();
}
public String getToughness() {
return toughness;
}
public String getStartingLoyalty() {
return startingLoyalty;
}
public String getSetCode() {
return setCode;
}
public String getClassName() {
return className;
}
public String getCardNumber() {
return cardNumber;
}
public int getCardNumberAsInt() {
return CardUtil.parseCardNumberAsInt(cardNumber);
}
public boolean isSplitCard() {
return splitCard;
}
public boolean isSplitFuseCard() {
return splitCardFuse;
}
public boolean isSplitAftermathCard() {
return splitCardAftermath;
}
public boolean isSplitCardHalf() {
return splitCardHalf;
}
public boolean isFlipCard() {
return flipCard;
}
public String getFlipCardName() {
return flipCardName;
}
public boolean isDoubleFaced() {
return doubleFaced;
}
public boolean isNightCard() {
return nightCard;
}
public String getSecondSideName() {
return secondSideName;
}
public boolean isAdventureCard() {
return adventureCard;
}
public String getAdventureSpellName() {
return adventureSpellName;
}
public boolean isModalDoubleFacesCard() {
return modalDoubleFacesCard;
}
public String getModalDoubleFacesSecondSideName() {
return modalDoubleFacesSecondSideName;
}
@Override
public String toString() {
return String.format("%s (%s, %s)", getName(), getSetCode(), getCardNumber());
}
}