mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-20 12:48:00 +00:00
TokenScript: make CardTextChange working again
SpellAbility: changeTextIntrinsic to sub abilities
This commit is contained in:
@@ -188,6 +188,21 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
|
||||
return supertypes.remove(st);
|
||||
}
|
||||
|
||||
public boolean remove(final String str) {
|
||||
boolean changed = false;
|
||||
if (CardType.isASupertype(str) && supertypes.remove(stringToSupertype.get(str))) {
|
||||
changed = true;
|
||||
} else if (CardType.isACardType(str) && coreTypes.remove(stringToCoreType.get(str))) {
|
||||
changed = true;
|
||||
} else if (subtypes.remove(str)) {
|
||||
changed = true;
|
||||
}
|
||||
if (changed) {
|
||||
calculatedType = null;
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
public boolean setCreatureTypes(Collection<String> ctypes) {
|
||||
// if it isn't a creature then this has no effect
|
||||
if (!isCreature() && !isTribal()) {
|
||||
|
||||
@@ -46,6 +46,11 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView {
|
||||
|
||||
protected Map<String, String> sVars = Maps.newHashMap();
|
||||
|
||||
protected Map<String, String> intrinsicChangedTextColors = Maps.newHashMap();
|
||||
protected Map<String, String> intrinsicChangedTextTypes = Maps.newHashMap();
|
||||
protected Map<String, String> changedTextColors = Maps.newHashMap();
|
||||
protected Map<String, String> changedTextTypes = Maps.newHashMap();
|
||||
|
||||
/** Keys of descriptive (text) parameters. */
|
||||
private static final ImmutableList<String> descriptiveKeys = ImmutableList.<String>builder()
|
||||
.add("Description", "SpellDescription", "StackDescription", "TriggerDescription").build();
|
||||
@@ -53,6 +58,11 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView {
|
||||
private static final ImmutableList<String> mutableKeys = ImmutableList.<String>builder()
|
||||
.add("AddAbility").build();
|
||||
|
||||
/**
|
||||
* Keys that should not changed
|
||||
*/
|
||||
private static final ImmutableList<String> noChangeKeys = ImmutableList.<String>builder()
|
||||
.add("TokenScript", "LegacyImage", "TokenImage").build();
|
||||
/**
|
||||
* Sets the temporary.
|
||||
*
|
||||
@@ -449,9 +459,15 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView {
|
||||
}
|
||||
|
||||
public void changeText() {
|
||||
// copy changed text words into card trait there
|
||||
this.changedTextColors = getHostCard().getChangedTextColorWords();
|
||||
this.changedTextTypes = getHostCard().getChangedTextTypeWords();
|
||||
|
||||
for (final String key : this.mapParams.keySet()) {
|
||||
final String value = this.originalMapParams.get(key), newValue;
|
||||
if (descriptiveKeys.contains(key)) {
|
||||
if (noChangeKeys.contains(key)) {
|
||||
continue;
|
||||
} else if (descriptiveKeys.contains(key)) {
|
||||
// change descriptions differently
|
||||
newValue = AbilityUtils.applyDescriptionTextChangeEffects(value, this);
|
||||
} else if (mutableKeys.contains(key)) {
|
||||
@@ -515,4 +531,53 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView {
|
||||
public Set<String> getSVars() {
|
||||
return sVars.keySet();
|
||||
}
|
||||
|
||||
public Map<String, String> getChangedTextColors() {
|
||||
return _combineChangedMap(intrinsicChangedTextColors, changedTextColors);
|
||||
}
|
||||
public Map<String, String> getChangedTextTypes() {
|
||||
return _combineChangedMap(intrinsicChangedTextTypes, changedTextTypes);
|
||||
}
|
||||
|
||||
private Map<String, String> _combineChangedMap(Map<String, String> input, Map<String, String> output) {
|
||||
// no need to do something, just return hash
|
||||
if (input.isEmpty()) {
|
||||
return output;
|
||||
}
|
||||
if (output.isEmpty()) {
|
||||
return input;
|
||||
}
|
||||
// magic combine them
|
||||
Map<String, String> result = Maps.newHashMap(output);
|
||||
for (Map.Entry<String, String> e : input.entrySet()) {
|
||||
String value = e.getValue();
|
||||
result.put(e.getKey(), output.containsKey(value) ? output.get(value) : value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void changeTextIntrinsic(Map<String,String> colorMap, Map<String,String> typeMap) {
|
||||
intrinsicChangedTextColors = colorMap;
|
||||
intrinsicChangedTextTypes = typeMap;
|
||||
for (final String key : this.mapParams.keySet()) {
|
||||
final String value = this.originalMapParams.get(key), newValue;
|
||||
if (noChangeKeys.contains(key)) {
|
||||
continue;
|
||||
} else if (descriptiveKeys.contains(key)) {
|
||||
// change descriptions differently
|
||||
newValue = AbilityUtils.applyTextChangeEffects(value, true, colorMap, typeMap);
|
||||
}else if (this.getHostCard().hasSVar(value)) {
|
||||
// don't change literal SVar names!
|
||||
continue;
|
||||
} else {
|
||||
newValue = AbilityUtils.applyTextChangeEffects(value, false, colorMap, typeMap);
|
||||
}
|
||||
|
||||
if (newValue != null) {
|
||||
this.mapParams.put(key, newValue);
|
||||
}
|
||||
}
|
||||
// this does overwrite the original MapParams
|
||||
this.originalMapParams = Maps.newHashMap(this.mapParams);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1724,12 +1724,18 @@ public class AbilityUtils {
|
||||
}
|
||||
|
||||
private static final String applyTextChangeEffects(final String def, final Card card, final boolean isDescriptive) {
|
||||
return applyTextChangeEffects(def, isDescriptive,
|
||||
card.getChangedTextColorWords(), card.getChangedTextTypeWords());
|
||||
}
|
||||
|
||||
public static final String applyTextChangeEffects(final String def, final boolean isDescriptive,
|
||||
Map<String,String> colorMap, Map<String,String> typeMap) {
|
||||
if (StringUtils.isEmpty(def)) {
|
||||
return def;
|
||||
}
|
||||
|
||||
String replaced = def;
|
||||
for (final Entry<String, String> e : card.getChangedTextColorWords().entrySet()) {
|
||||
for (final Entry<String, String> e : colorMap.entrySet()) {
|
||||
final String key = e.getKey();
|
||||
String value;
|
||||
if (key.equals("Any")) {
|
||||
@@ -1750,7 +1756,7 @@ public class AbilityUtils {
|
||||
replaced = replaced.replaceAll("(?<!>)" + key, value);
|
||||
}
|
||||
}
|
||||
for (final Entry<String, String> e : card.getChangedTextTypeWords().entrySet()) {
|
||||
for (final Entry<String, String> e : typeMap.entrySet()) {
|
||||
final String key = e.getKey();
|
||||
final String pkey = CardType.getPluralType(key);
|
||||
final String pvalue = getReplacedText(pkey, CardType.getPluralType(e.getValue()), isDescriptive);
|
||||
|
||||
@@ -3640,6 +3640,12 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
}
|
||||
}
|
||||
|
||||
public final void removeIntrinsicKeyword(final KeywordInterface s) {
|
||||
if (currentState.removeIntrinsicKeyword(s)) {
|
||||
currentState.getView().updateKeywords(this, currentState);
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<KeywordInterface> getExtrinsicKeyword() {
|
||||
return extrinsicKeyword.getValues();
|
||||
}
|
||||
|
||||
@@ -7,8 +7,6 @@ import java.util.SortedMap;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import forge.card.CardType;
|
||||
|
||||
public final class CardChangedWords {
|
||||
|
||||
private final SortedMap<Long, CardChangedWord> map = Maps.newTreeMap();
|
||||
@@ -68,14 +66,9 @@ public final class CardChangedWords {
|
||||
|
||||
// the actual change (b->c)
|
||||
resultCache.put(ccw.getOriginalWord(), ccw.getNewWord());
|
||||
|
||||
// possible plural form
|
||||
final String singular = CardType.getPluralType(ccw.getOriginalWord());
|
||||
if (!singular.equals(ccw.getOriginalWord())) {
|
||||
resultCache.put(singular, ccw.getNewWord());
|
||||
}
|
||||
}
|
||||
|
||||
// TODO should that be removed?
|
||||
for (final String key : ImmutableList.copyOf(resultCache.keySet())) {
|
||||
if (!key.equals("Any")) {
|
||||
resultCache.put(key.toLowerCase(), resultCache.get(key).toLowerCase());
|
||||
|
||||
@@ -231,6 +231,9 @@ public class CardState extends GameObject {
|
||||
public final boolean removeIntrinsicKeyword(final String s) {
|
||||
return intrinsicKeywords.remove(s);
|
||||
}
|
||||
public final boolean removeIntrinsicKeyword(final KeywordInterface s) {
|
||||
return intrinsicKeywords.remove(s);
|
||||
}
|
||||
|
||||
public final FCollectionView<SpellAbility> getSpellAbilities() {
|
||||
FCollection<SpellAbility> newCol = new FCollection<SpellAbility>(manaAbilities);
|
||||
@@ -554,4 +557,19 @@ public class CardState extends GameObject {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void changeTextIntrinsic(Map<String,String> colorMap, Map<String,String> typeMap) {
|
||||
final List<CardTraitBase> allAbs = ImmutableList.<CardTraitBase>builder()
|
||||
.addAll(manaAbilities)
|
||||
.addAll(nonManaAbilities)
|
||||
.addAll(triggers)
|
||||
.addAll(replacementEffects)
|
||||
.addAll(staticAbilities)
|
||||
.build();
|
||||
for (final CardTraitBase ctb : allAbs) {
|
||||
if (ctb.isIntrinsic()) {
|
||||
ctb.changeTextIntrinsic(colorMap, typeMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,6 +281,8 @@ public final class CardUtil {
|
||||
newCopy.setChangedCardKeywords(in.getChangedCardKeywords());
|
||||
newCopy.setChangedCardTypes(in.getChangedCardTypesMap());
|
||||
|
||||
newCopy.copyChangedTextFrom(in);
|
||||
|
||||
newCopy.setMeldedWith(in.getMeldedWith());
|
||||
|
||||
newCopy.setTimestamp(in.getTimestamp());
|
||||
|
||||
@@ -12,6 +12,7 @@ import forge.game.Game;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardFactory;
|
||||
import forge.game.card.CardFactoryUtil;
|
||||
import forge.game.card.CardUtil;
|
||||
import forge.game.keyword.KeywordInterface;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
@@ -20,6 +21,8 @@ import forge.item.PaperToken;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
public class TokenInfo {
|
||||
final String name;
|
||||
final String imageName;
|
||||
@@ -229,10 +232,121 @@ public class TokenInfo {
|
||||
String edition = host.getSetCode();
|
||||
PaperToken token = StaticData.instance().getAllTokens().getToken(script, edition);
|
||||
|
||||
// TODO add Card Text Change from SpellAbility
|
||||
|
||||
if (token != null) {
|
||||
return Card.fromPaperCard(token, null, game);
|
||||
final Card result = Card.fromPaperCard(token, null, game);
|
||||
|
||||
// update Token with CardTextChanges
|
||||
Map<String, String> colorMap = sa.getChangedTextColors();
|
||||
Map<String, String> typeMap = sa.getChangedTextTypes();
|
||||
if (!colorMap.isEmpty()) {
|
||||
if (!result.isColorless()) {
|
||||
// change Token Colors
|
||||
byte color = CardUtil.getColors(result).getColor();
|
||||
|
||||
for (final Map.Entry<String, String> e : colorMap.entrySet()) {
|
||||
byte v = MagicColor.fromName(e.getValue());
|
||||
// Any used by Swirl the Mists
|
||||
if ("Any".equals(e.getKey())) {
|
||||
for (final byte c : MagicColor.WUBRG) {
|
||||
// try to replace color flips
|
||||
if ((color & c) != 0) {
|
||||
color &= ~c;
|
||||
color |= v;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
byte c = MagicColor.fromName(e.getKey());
|
||||
// try to replace color flips
|
||||
if ((color & c) != 0) {
|
||||
color &= ~c;
|
||||
color |= v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result.setColor(color);
|
||||
}
|
||||
}
|
||||
if (!typeMap.isEmpty()) {
|
||||
String oldName = result.getName();
|
||||
|
||||
CardType type = new CardType(result.getType());
|
||||
String joinedName = StringUtils.join(type.getSubtypes(), " ");
|
||||
final boolean nameGenerated = oldName.equals(joinedName);
|
||||
boolean typeChanged = false;
|
||||
|
||||
if (!Iterables.isEmpty(type.getSubtypes())) {
|
||||
for (final Map.Entry<String, String> e : typeMap.entrySet()) {
|
||||
if (type.hasSubtype(e.getKey())) {
|
||||
type.remove(e.getKey());
|
||||
type.add(e.getValue());
|
||||
typeChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (typeChanged) {
|
||||
result.setType(type);
|
||||
|
||||
// update generated Name
|
||||
if (nameGenerated) {
|
||||
result.setName(StringUtils.join(type.getSubtypes(), " "));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// replace Intrinsic Keyword
|
||||
List<KeywordInterface> toRemove = Lists.newArrayList();
|
||||
List<String> toAdd = Lists.newArrayList();
|
||||
for (final KeywordInterface k : result.getCurrentState().getIntrinsicKeywords()) {
|
||||
final String o = k.getOriginal();
|
||||
// only Modifiable should go there
|
||||
if (!CardUtil.isKeywordModifiable(o)) {
|
||||
continue;
|
||||
}
|
||||
String r = new String(o);
|
||||
// replace types
|
||||
for (final Map.Entry<String, String> e : typeMap.entrySet()) {
|
||||
final String key = e.getKey();
|
||||
final String pkey = CardType.getPluralType(key);
|
||||
final String value = e.getValue();
|
||||
final String pvalue = CardType.getPluralType(e.getValue());
|
||||
r = r.replaceAll(pkey, pvalue);
|
||||
r = r.replaceAll(key, value);
|
||||
}
|
||||
// replace color words
|
||||
for (final Map.Entry<String, String> e : colorMap.entrySet()) {
|
||||
final String vName = e.getValue();
|
||||
final String vCaps = StringUtils.capitalize(vName);
|
||||
final String vLow = vName.toLowerCase();
|
||||
if ("Any".equals(e.getKey())) {
|
||||
for (final byte c : MagicColor.WUBRG) {
|
||||
final String cName = MagicColor.toLongString(c);
|
||||
final String cNameCaps = StringUtils.capitalize(cName);
|
||||
final String cNameLow = cName.toLowerCase();
|
||||
r = r.replaceAll(cNameCaps, vCaps);
|
||||
r = r.replaceAll(cNameLow, vLow);
|
||||
}
|
||||
} else {
|
||||
final String cName = e.getKey();
|
||||
final String cNameCaps = StringUtils.capitalize(cName);
|
||||
final String cNameLow = cName.toLowerCase();
|
||||
r = r.replaceAll(cNameCaps, vCaps);
|
||||
r = r.replaceAll(cNameLow, vLow);
|
||||
}
|
||||
}
|
||||
if (!r.equals(o)) {
|
||||
toRemove.add(k);
|
||||
toAdd.add(r);
|
||||
}
|
||||
}
|
||||
for (final KeywordInterface k : toRemove) {
|
||||
result.getCurrentState().removeIntrinsicKeyword(k);
|
||||
}
|
||||
result.addIntrinsicKeywords(toAdd);
|
||||
|
||||
result.getCurrentState().changeTextIntrinsic(colorMap, typeMap);
|
||||
return result;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -96,6 +96,10 @@ public class KeywordCollection implements Iterable<String>, Serializable {
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean remove(KeywordInterface keyword) {
|
||||
return map.remove(keyword.getKeyword(), keyword);
|
||||
}
|
||||
|
||||
public boolean removeAll(Iterable<String> keywords) {
|
||||
boolean result = false;
|
||||
for (String k : keywords) {
|
||||
|
||||
@@ -1709,6 +1709,31 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.game.CardTraitBase#changeTextIntrinsic(java.util.Map, java.util.Map)
|
||||
*/
|
||||
@Override
|
||||
public void changeTextIntrinsic(Map<String, String> colorMap, Map<String, String> typeMap) {
|
||||
super.changeTextIntrinsic(colorMap, typeMap);
|
||||
|
||||
if (subAbility != null) {
|
||||
// if the parent of the subability is not this,
|
||||
// then there might be a loop
|
||||
if (subAbility.getParent() == this) {
|
||||
subAbility.changeTextIntrinsic(colorMap, typeMap);
|
||||
}
|
||||
}
|
||||
for (AbilitySub sa : additionalAbilities.values()) {
|
||||
sa.changeTextIntrinsic(colorMap, typeMap);
|
||||
}
|
||||
|
||||
for (List<AbilitySub> list : additionalAbilityLists.values()) {
|
||||
for (AbilitySub sa : list) {
|
||||
sa.changeTextIntrinsic(colorMap, typeMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIntrinsic(boolean i) {
|
||||
super.setIntrinsic(i);
|
||||
|
||||
@@ -169,11 +169,7 @@ public abstract class Trigger extends TriggerReplacementBase {
|
||||
if (!desc.contains("ABILITY")) {
|
||||
return desc;
|
||||
}
|
||||
SpellAbility sa = getOverridingAbility();
|
||||
if (sa == null && this.mapParams.containsKey("Execute")) {
|
||||
sa = AbilityFactory.getAbility(state, this.mapParams.get("Execute"));
|
||||
setOverridingAbility(sa);
|
||||
}
|
||||
SpellAbility sa = ensureAbility();
|
||||
|
||||
return replaceAbilityText(desc, sa);
|
||||
|
||||
@@ -583,4 +579,48 @@ public abstract class Trigger extends TriggerReplacementBase {
|
||||
throw new RuntimeException("Trigger : clone() error, " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.game.CardTraitBase#changeText()
|
||||
*/
|
||||
@Override
|
||||
public void changeText() {
|
||||
if (!isIntrinsic()) {
|
||||
return;
|
||||
}
|
||||
super.changeText();
|
||||
|
||||
ensureAbility();
|
||||
|
||||
if (getOverridingAbility() != null) {
|
||||
getOverridingAbility().changeText();
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.game.CardTraitBase#changeTextIntrinsic(java.util.Map, java.util.Map)
|
||||
*/
|
||||
@Override
|
||||
public void changeTextIntrinsic(Map<String, String> colorMap, Map<String, String> typeMap) {
|
||||
if (!isIntrinsic()) {
|
||||
return;
|
||||
}
|
||||
super.changeTextIntrinsic(colorMap, typeMap);
|
||||
|
||||
ensureAbility();
|
||||
|
||||
if (getOverridingAbility() != null) {
|
||||
getOverridingAbility().changeTextIntrinsic(colorMap, typeMap);
|
||||
}
|
||||
}
|
||||
|
||||
private SpellAbility ensureAbility() {
|
||||
SpellAbility sa = getOverridingAbility();
|
||||
if (sa == null && hasParam("Execute")) {
|
||||
sa = AbilityFactory.getAbility(getHostCard(), getParam("Execute"));
|
||||
setOverridingAbility(sa);
|
||||
}
|
||||
return sa;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user