Support saving/restoring game state that has creature tokens.

This commit is contained in:
Myrd
2015-01-03 19:15:44 +00:00
parent 06801023b5
commit 2853af3a10
5 changed files with 153 additions and 33 deletions

View File

@@ -14,6 +14,7 @@ import forge.game.Game;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardFactory;
import forge.game.card.CounterType;
import forge.game.phase.PhaseType;
import forge.game.player.Player;
@@ -94,7 +95,11 @@ public abstract class GameState {
if (newText.length() > 0) {
newText.append(";");
}
newText.append(c.getName());
if (c.isToken()) {
newText.append("t:" + new CardFactory.TokenInfo(c).toString());
} else {
newText.append(c.getName());
}
if (zoneType == ZoneType.Battlefield) {
if (c.isTapped()) {
newText.append("|Tapped:True");
@@ -206,8 +211,17 @@ public abstract class GameState {
if (life > 0) p.setLife(life, null);
for (Entry<ZoneType, CardCollectionView> kv : playerCards.entrySet()) {
if (kv.getKey() == ZoneType.Battlefield) {
p.getZone(kv.getKey()).setCards(new ArrayList<Card>());
ArrayList<Card> cards = new ArrayList<Card>();
for (final Card c : kv.getValue()) {
if (c.isToken()) {
cards.add(c);
}
}
p.getZone(kv.getKey()).setCards(cards);
for (final Card c : kv.getValue()) {
if (c.isToken()) {
continue;
}
boolean tapped = c.isTapped();
boolean sickness = c.hasSickness();
p.getZone(ZoneType.Hand).add(c);
@@ -237,8 +251,15 @@ public abstract class GameState {
for (final String element : data) {
final String[] cardinfo = element.trim().split("\\|");
//System.out.println("paper card " + cardinfo[0]);
final Card c = Card.fromPaperCard(getPaperCard(cardinfo[0]), player);
Card c;
if (cardinfo[0].startsWith("t:")) {
String tokenStr = cardinfo[0].substring(2);
// TODO: Use a version of the API that doesn't return a list (i.e. these shouldn't be affected
// by doubling season, etc).
c = CardFactory.makeToken(CardFactory.TokenInfo.fromString(tokenStr), player).get(0);
} else {
c = Card.fromPaperCard(getPaperCard(cardinfo[0]), player);
}
boolean hasSetCurSet = false;
for (final String info : cardinfo) {
@@ -259,7 +280,7 @@ public abstract class GameState {
}
}
if (!hasSetCurSet) {
if (!hasSetCurSet && !c.isToken()) {
c.setSetCode(c.getMostRecentSet());
}

View File

@@ -368,9 +368,10 @@ public class TokenAi extends SpellAbilityAi {
}
}
final String substitutedName = tokenName.equals("ChosenType") ? host.getChosenType() : tokenName;
final List<Card> tokens = CardFactory.makeToken(substitutedName,
imageNames.get(MyRandom.getRandom().nextInt(imageNames.size())),
ai, cost, substitutedTypes, finalPower, finalToughness, tokenKeywords);
final String imageName = imageNames.get(MyRandom.getRandom().nextInt(imageNames.size()));
final CardFactory.TokenInfo tokenInfo = new CardFactory.TokenInfo(substitutedName, imageName,
cost, substitutedTypes, tokenKeywords, finalPower, finalToughness);
final List<Card> tokens = CardFactory.makeToken(tokenInfo, ai);
// Grant rule changes
if (tokenHiddenKeywords != null) {

View File

@@ -87,6 +87,13 @@ public class ImageKeys {
return ImageKeys.TOKEN_PREFIX + tokenName;
}
public static String getTokenImageName(String tokenKey) {
if (!tokenKey.startsWith(ImageKeys.TOKEN_PREFIX)) {
return null;
}
return tokenKey.substring(ImageKeys.TOKEN_PREFIX.length());
}
public static File getImageFile(String key) {
if (StringUtils.isEmpty(key)) {
return null;

View File

@@ -226,10 +226,11 @@ public class TokenEffect extends SpellAbilityEffect {
final boolean imprint = sa.hasParam("ImprintTokens");
for (final Player controller : AbilityUtils.getDefinedPlayers(host, this.tokenOwner, sa)) {
for (int i = 0; i < finalAmount; i++) {
final List<Card> tokens = CardFactory.makeToken(substitutedName,
imageNames.get(MyRandom.getRandom().nextInt(imageNames.size())),
controller, cost, substitutedTypes, finalPower, finalToughness, this.tokenKeywords);
for(Card tok : tokens) {
final String imageName = imageNames.get(MyRandom.getRandom().nextInt(imageNames.size()));
final CardFactory.TokenInfo tokenInfo = new CardFactory.TokenInfo(substitutedName, imageName,
cost, substitutedTypes, this.tokenKeywords, finalPower, finalToughness);
final List<Card> tokens = CardFactory.makeToken(tokenInfo, controller);
for (Card tok : tokens) {
if (this.tokenTapped) {
tok.setTapped(true);
}

View File

@@ -22,6 +22,7 @@ import forge.card.CardStateName;
import forge.card.CardRules;
import forge.card.CardSplitType;
import forge.card.CardType;
import forge.card.CardType.CoreType;
import forge.card.ICardFace;
import forge.card.mana.ManaCost;
import forge.game.Game;
@@ -45,6 +46,9 @@ import java.util.Arrays;
import java.util.List;
import java.util.Map.Entry;
import com.google.common.base.Joiner;
import com.google.common.collect.Iterables;
/**
* <p>
* AbstractCardFactory class.
@@ -605,31 +609,116 @@ public class CardFactory {
}
}
public static List<Card> makeToken(final String name, final String imageName, final Player controller,
final String manaCost, final String[] types, final int basePower, final int baseToughness,
final String[] intrinsicKeywords) {
final List<Card> list = new ArrayList<Card>();
final Card c = new Card(controller.getGame().nextCardId(), controller.getGame());
c.setName(name);
c.setImageKey(ImageKeys.getTokenKey(imageName));
public static class TokenInfo {
final String name;
final String imageName;
final String manaCost;
final String[] types;
final String[] intrinsicKeywords;
final int basePower;
final int baseToughness;
// TODO - most tokens mana cost is 0, this needs to be fixed
// c.setManaCost(manaCost);
c.addColor(manaCost);
c.setToken(true);
for (final String t : types) {
c.addType(t);
public TokenInfo(String name, String imageName, String manaCost, String[] types,
String[] intrinsicKeywords, int basePower, int baseToughness) {
this.name = name;
this.imageName = imageName;
this.manaCost = manaCost;
this.types = types;
this.intrinsicKeywords = intrinsicKeywords;
this.basePower = basePower;
this.baseToughness = baseToughness;
}
c.setBasePower(basePower);
c.setBaseToughness(baseToughness);
public TokenInfo(Card c) {
this.name = c.getName();
this.imageName = ImageKeys.getTokenImageName(c.getImageKey());
this.manaCost = c.getManaCost().toString();
this.types = getCardTypes(c);
this.intrinsicKeywords = c.getKeywords().toArray(new String[0]);
this.basePower = c.getBasePower();
this.baseToughness = c.getBaseToughness();
}
private static String[] getCardTypes(Card c) {
ArrayList<String> relevantTypes = new ArrayList<String>();
for (CoreType t : c.getType().getCoreTypes()) {
relevantTypes.add(t.name());
}
Iterables.addAll(relevantTypes, c.getType().getSubtypes());
return relevantTypes.toArray(new String[relevantTypes.size()]);
}
private Card toCard(Game game) {
final Card c = new Card(game.nextCardId(), game);
c.setName(name);
c.setImageKey(ImageKeys.getTokenKey(imageName));
// TODO - most tokens mana cost is 0, this needs to be fixed
// c.setManaCost(manaCost);
c.addColor(manaCost);
c.setToken(true);
for (final String t : types) {
c.addType(t);
}
c.setBasePower(basePower);
c.setBaseToughness(baseToughness);
return c;
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(name).append(',');
sb.append("P:").append(basePower).append(',');
sb.append("T:").append(baseToughness).append(',');
sb.append("Cost:").append(manaCost).append(',');
sb.append("Types:").append(Joiner.on('-').join(types)).append(',');
sb.append("Keywords:").append(Joiner.on('-').join(intrinsicKeywords)).append(',');
sb.append("Image:").append(imageName);
return sb.toString();
}
public static TokenInfo fromString(String str) {
final String[] tokenInfo = str.split(",");
int power = 0;
int toughness = 0;
String manaCost = "0";
String[] types = null;
String[] keywords = null;
String imageName = null;
for (String info : tokenInfo) {
int index = info.indexOf(':');
if (index == -1) {
continue;
}
String remainder = info.substring(index + 1);
if (info.startsWith("P:")) {
power = Integer.parseInt(remainder);
} else if (info.startsWith("T:")) {
toughness = Integer.parseInt(remainder);
} else if (info.startsWith("Cost:")) {
manaCost = remainder;
} else if (info.startsWith("Types:")) {
types = remainder.split("-");
} else if (info.startsWith("Keywords:")) {
keywords = remainder.split("-");
} else if (info.startsWith("Image:")) {
imageName = remainder;
}
}
return new TokenInfo(tokenInfo[0], imageName, manaCost, types, keywords, power, toughness);
}
}
public static List<Card> makeToken(final TokenInfo tokenInfo, final Player controller) {
final List<Card> list = new ArrayList<Card>();
final Card c = tokenInfo.toCard(controller.getGame());
final int multiplier = controller.getTokenDoublersMagnitude();
for (int i = 0; i < multiplier; i++) {
Card temp = copyStats(c, controller);
for (final String kw : intrinsicKeywords) {
for (final String kw : tokenInfo.intrinsicKeywords) {
temp.addIntrinsicKeyword(kw);
}
temp.setOwner(controller);
@@ -640,6 +729,7 @@ public class CardFactory {
}
return list;
}
/**
* Copy triggered ability
*