Flavor Names (#8849)

* Make getAllFaces return nonnull list

* Optimize Predicates

* CardDB and script syntax changes

* Apply syntax changes

* In-game support for flavor names

* Add display names to PaperCards

* Support searching by flavor names

* Remove some WIP stuff

* Update PaperCard translation key.

* Update capitalization

* Auto-map to variants when edition entry uses a flavor name

* Consolidate display name logic.

* Added syntax for generating flavor named variants in edition files.

* Some examples of new syntax.

* Ignore flavored oracle text when searching rules text

* add hasFlavorName

* Add image key

* Get correct variant from card requests with flavor names.
This commit is contained in:
Jetz72
2025-10-21 09:00:59 -04:00
committed by GitHub
parent 1188b6889a
commit f9b6652c2a
90 changed files with 898 additions and 626 deletions

View File

@@ -271,7 +271,7 @@ public class GameFormat implements Comparable<GameFormat> {
if (erroneousCI.size() > 0) {
final StringBuilder sb = new StringBuilder("contains the following illegal cards:\n");
for (final PaperCard cp : erroneousCI) {
sb.append("\n").append(cp.getName());
sb.append("\n").append(cp.getDisplayName());
}
return sb.toString();
}
@@ -290,7 +290,7 @@ public class GameFormat implements Comparable<GameFormat> {
if (erroneousRestricted.size() > 0) {
final StringBuilder sb = new StringBuilder("contains more than one copy of the following restricted cards:\n");
for (final PaperCard cp : erroneousRestricted) {
sb.append("\n").append(cp.getName());
sb.append("\n").append(cp.getDisplayName());
}
return sb.toString();
}

View File

@@ -91,10 +91,10 @@ public class AlterAttributeEffect extends SpellAbilityEffect {
}
p.addCommander(gameCard);
//Seems important enough to mention in the game log.
gameCard.getGame().getGameLog().add(GameLogEntryType.STACK_RESOLVE, String.format("%s is now %s's commander.", gameCard.getPaperCard().getName(), p));
gameCard.getGame().getGameLog().add(GameLogEntryType.STACK_RESOLVE, String.format("%s is now %s's commander.", gameCard.getPaperCard().getDisplayName(), p));
} else {
p.removeCommander(gameCard);
gameCard.getGame().getGameLog().add(GameLogEntryType.STACK_RESOLVE, String.format("%s is no longer %s's commander.", gameCard.getPaperCard().getName(), p));
gameCard.getGame().getGameLog().add(GameLogEntryType.STACK_RESOLVE, String.format("%s is no longer %s's commander.", gameCard.getPaperCard().getDisplayName(), p));
}
altered = true;
break;

View File

@@ -952,23 +952,28 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
@Override
public final String getName() {
return getName(currentState, false);
return getName(currentState);
}
public final String getName(boolean alt) {
return getName(currentState, alt);
}
public final String getName(CardStateName stateName) {
return getName(getState(stateName), false);
}
public final String getName(CardState state, boolean alt) {
public final String getName(CardState state) {
String name = state.getName();
for (CardChangedName change : this.changedCardNames.values()) {
if (change.isOverwrite()) {
name = change.newName();
}
}
return alt ? StaticData.instance().getCommonCards().getName(name, true) : name;
return name;
}
public final String getDisplayName() {
return getDisplayName(currentState);
}
public final String getDisplayName(CardState state) {
//If this card has a changed name, don't use flavor names.
if(state.getFlavorName() == null || hasNameOverwrite())
return getName(state);
return state.getFlavorName();
}
public final boolean hasNameOverwrite() {
@@ -6058,7 +6063,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
return true;
}
}
return sharesNameWith(c1.getName(true));
return sharesNameWith(c1.getName());
}
public final boolean sharesNameWith(final String name) {
@@ -6067,7 +6072,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
return false;
}
boolean shares = getName(true).equals(name);
boolean shares = getName().equals(name);
// Split cards has extra logic to check if it does share a name with
if (!shares && !hasNameOverwrite()) {
@@ -7844,7 +7849,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
}
@Override
public String getUntranslatedName() {
return this.getName();
return this.getDisplayName();
}
@Override
public String getUntranslatedType() {

View File

@@ -402,6 +402,8 @@ public class CardFactory {
c.getCurrentState().setOracleText(face.getOracleText());
c.getCurrentState().setFlavorName(face.getFlavorName());
// Super and 'middle' types should use enums.
c.setType(new CardType(face.getType()));

View File

@@ -63,6 +63,7 @@ public class CardState implements GameObject, IHasSVars, ITranslatable {
private ColorSet color = ColorSet.C;
private String oracleText = "";
private String functionalVariantName = null;
private String flavorName = null;
private int basePower = 0;
private int baseToughness = 0;
private String basePowerString = null;
@@ -221,6 +222,15 @@ public class CardState implements GameObject, IHasSVars, ITranslatable {
view.setFunctionalVariantName(functionalVariantName);
}
public String getFlavorName() {
return flavorName;
}
public void setFlavorName(String flavorName) {
this.flavorName = flavorName;
view.updateName(this);
}
public final int getBasePower() {
return basePower;
}
@@ -716,6 +726,7 @@ public class CardState implements GameObject, IHasSVars, ITranslatable {
setBaseLoyalty(source.getBaseLoyalty());
setBaseDefense(source.getBaseDefense());
setAttractionLights(source.getAttractionLights());
setFlavorName(source.getFlavorName());
setSVars(source.getSVars());
abilities.clear();
@@ -930,9 +941,10 @@ public class CardState implements GameObject, IHasSVars, ITranslatable {
@Override
public String getTranslationKey() {
String displayName = flavorName == null ? name : flavorName;
if(StringUtils.isNotEmpty(functionalVariantName))
return name + " $" + functionalVariantName;
return name;
return displayName + " $" + functionalVariantName;
return displayName;
}
@Override

View File

@@ -7,10 +7,7 @@ import forge.ImageKeys;
import forge.StaticData;
import forge.card.*;
import forge.card.mana.ManaCost;
import forge.game.Direction;
import forge.game.EvenOdd;
import forge.game.GameEntityView;
import forge.game.GameType;
import forge.game.*;
import forge.game.combat.Combat;
import forge.game.keyword.Keyword;
import forge.game.player.Player;
@@ -100,6 +97,25 @@ public class CardView extends GameEntityView {
set(TrackableProperty.Controller, ownerAndController);
set(TrackableProperty.ImageKey, imageKey);
}
@Override
protected void updateName(GameEntity e) {
//Name reflects the current display name, as modified by any flavor names.
//OracleName can be used to find the true name of a card.
if (e instanceof Card c) {
set(TrackableProperty.Name, c.getDisplayName());
set(TrackableProperty.OracleName, c.getName());
}
else {
super.updateName(e);
set(TrackableProperty.OracleName, e.getName());
}
}
public String getOracleName() {
return get(TrackableProperty.OracleName);
}
public PlayerView getOwner() {
return get(TrackableProperty.Owner);
}
@@ -1280,16 +1296,26 @@ public class CardView extends GameEntityView {
}
void updateName(CardState c) {
Card card = c.getCard();
setName(card.getName(c, false));
setName(card.getDisplayName(c));
setOracleName(card.getName(c));
if (CardView.this.getCurrentState() == this) {
if (card != null) {
CardView.this.updateName(card);
}
CardView.this.updateName(card);
}
}
private void setName(String name0) {
set(TrackableProperty.Name, name0);
private void setName(String name) {
set(TrackableProperty.Name, name);
}
/**
* @return The name of the card, unaltered by flavor names.
*/
public String getOracleName() {
return get(TrackableProperty.OracleName);
}
private void setOracleName(String name) {
set(TrackableProperty.OracleName, name);
}
public ColorSet getColors() {

View File

@@ -131,6 +131,7 @@ public enum TrackableProperty {
FunctionalVariant(TrackableTypes.StringType),
OracleText(TrackableTypes.StringType),
RulesText(TrackableTypes.StringType),
OracleName(TrackableTypes.StringType),
Power(TrackableTypes.IntegerType),
Toughness(TrackableTypes.IntegerType),
Loyalty(TrackableTypes.StringType),