mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-18 11:48:02 +00:00
Support saving/restoring game state that has creature tokens.
This commit is contained in:
@@ -14,6 +14,7 @@ import forge.game.Game;
|
|||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.card.CardCollection;
|
import forge.game.card.CardCollection;
|
||||||
import forge.game.card.CardCollectionView;
|
import forge.game.card.CardCollectionView;
|
||||||
|
import forge.game.card.CardFactory;
|
||||||
import forge.game.card.CounterType;
|
import forge.game.card.CounterType;
|
||||||
import forge.game.phase.PhaseType;
|
import forge.game.phase.PhaseType;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
@@ -94,7 +95,11 @@ public abstract class GameState {
|
|||||||
if (newText.length() > 0) {
|
if (newText.length() > 0) {
|
||||||
newText.append(";");
|
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 (zoneType == ZoneType.Battlefield) {
|
||||||
if (c.isTapped()) {
|
if (c.isTapped()) {
|
||||||
newText.append("|Tapped:True");
|
newText.append("|Tapped:True");
|
||||||
@@ -206,8 +211,17 @@ public abstract class GameState {
|
|||||||
if (life > 0) p.setLife(life, null);
|
if (life > 0) p.setLife(life, null);
|
||||||
for (Entry<ZoneType, CardCollectionView> kv : playerCards.entrySet()) {
|
for (Entry<ZoneType, CardCollectionView> kv : playerCards.entrySet()) {
|
||||||
if (kv.getKey() == ZoneType.Battlefield) {
|
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()) {
|
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 tapped = c.isTapped();
|
||||||
boolean sickness = c.hasSickness();
|
boolean sickness = c.hasSickness();
|
||||||
p.getZone(ZoneType.Hand).add(c);
|
p.getZone(ZoneType.Hand).add(c);
|
||||||
@@ -237,8 +251,15 @@ public abstract class GameState {
|
|||||||
for (final String element : data) {
|
for (final String element : data) {
|
||||||
final String[] cardinfo = element.trim().split("\\|");
|
final String[] cardinfo = element.trim().split("\\|");
|
||||||
|
|
||||||
//System.out.println("paper card " + cardinfo[0]);
|
Card c;
|
||||||
final Card c = Card.fromPaperCard(getPaperCard(cardinfo[0]), player);
|
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;
|
boolean hasSetCurSet = false;
|
||||||
for (final String info : cardinfo) {
|
for (final String info : cardinfo) {
|
||||||
@@ -259,7 +280,7 @@ public abstract class GameState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasSetCurSet) {
|
if (!hasSetCurSet && !c.isToken()) {
|
||||||
c.setSetCode(c.getMostRecentSet());
|
c.setSetCode(c.getMostRecentSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -368,9 +368,10 @@ public class TokenAi extends SpellAbilityAi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
final String substitutedName = tokenName.equals("ChosenType") ? host.getChosenType() : tokenName;
|
final String substitutedName = tokenName.equals("ChosenType") ? host.getChosenType() : tokenName;
|
||||||
final List<Card> tokens = CardFactory.makeToken(substitutedName,
|
final String imageName = imageNames.get(MyRandom.getRandom().nextInt(imageNames.size()));
|
||||||
imageNames.get(MyRandom.getRandom().nextInt(imageNames.size())),
|
final CardFactory.TokenInfo tokenInfo = new CardFactory.TokenInfo(substitutedName, imageName,
|
||||||
ai, cost, substitutedTypes, finalPower, finalToughness, tokenKeywords);
|
cost, substitutedTypes, tokenKeywords, finalPower, finalToughness);
|
||||||
|
final List<Card> tokens = CardFactory.makeToken(tokenInfo, ai);
|
||||||
|
|
||||||
// Grant rule changes
|
// Grant rule changes
|
||||||
if (tokenHiddenKeywords != null) {
|
if (tokenHiddenKeywords != null) {
|
||||||
|
|||||||
@@ -87,6 +87,13 @@ public class ImageKeys {
|
|||||||
return ImageKeys.TOKEN_PREFIX + tokenName;
|
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) {
|
public static File getImageFile(String key) {
|
||||||
if (StringUtils.isEmpty(key)) {
|
if (StringUtils.isEmpty(key)) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -226,10 +226,11 @@ public class TokenEffect extends SpellAbilityEffect {
|
|||||||
final boolean imprint = sa.hasParam("ImprintTokens");
|
final boolean imprint = sa.hasParam("ImprintTokens");
|
||||||
for (final Player controller : AbilityUtils.getDefinedPlayers(host, this.tokenOwner, sa)) {
|
for (final Player controller : AbilityUtils.getDefinedPlayers(host, this.tokenOwner, sa)) {
|
||||||
for (int i = 0; i < finalAmount; i++) {
|
for (int i = 0; i < finalAmount; i++) {
|
||||||
final List<Card> tokens = CardFactory.makeToken(substitutedName,
|
final String imageName = imageNames.get(MyRandom.getRandom().nextInt(imageNames.size()));
|
||||||
imageNames.get(MyRandom.getRandom().nextInt(imageNames.size())),
|
final CardFactory.TokenInfo tokenInfo = new CardFactory.TokenInfo(substitutedName, imageName,
|
||||||
controller, cost, substitutedTypes, finalPower, finalToughness, this.tokenKeywords);
|
cost, substitutedTypes, this.tokenKeywords, finalPower, finalToughness);
|
||||||
for(Card tok : tokens) {
|
final List<Card> tokens = CardFactory.makeToken(tokenInfo, controller);
|
||||||
|
for (Card tok : tokens) {
|
||||||
if (this.tokenTapped) {
|
if (this.tokenTapped) {
|
||||||
tok.setTapped(true);
|
tok.setTapped(true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import forge.card.CardStateName;
|
|||||||
import forge.card.CardRules;
|
import forge.card.CardRules;
|
||||||
import forge.card.CardSplitType;
|
import forge.card.CardSplitType;
|
||||||
import forge.card.CardType;
|
import forge.card.CardType;
|
||||||
|
import forge.card.CardType.CoreType;
|
||||||
import forge.card.ICardFace;
|
import forge.card.ICardFace;
|
||||||
import forge.card.mana.ManaCost;
|
import forge.card.mana.ManaCost;
|
||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
@@ -45,6 +46,9 @@ import java.util.Arrays;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
import com.google.common.base.Joiner;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* AbstractCardFactory class.
|
* AbstractCardFactory class.
|
||||||
@@ -605,31 +609,116 @@ public class CardFactory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<Card> makeToken(final String name, final String imageName, final Player controller,
|
public static class TokenInfo {
|
||||||
final String manaCost, final String[] types, final int basePower, final int baseToughness,
|
final String name;
|
||||||
final String[] intrinsicKeywords) {
|
final String imageName;
|
||||||
final List<Card> list = new ArrayList<Card>();
|
final String manaCost;
|
||||||
final Card c = new Card(controller.getGame().nextCardId(), controller.getGame());
|
final String[] types;
|
||||||
c.setName(name);
|
final String[] intrinsicKeywords;
|
||||||
c.setImageKey(ImageKeys.getTokenKey(imageName));
|
final int basePower;
|
||||||
|
final int baseToughness;
|
||||||
|
|
||||||
// TODO - most tokens mana cost is 0, this needs to be fixed
|
public TokenInfo(String name, String imageName, String manaCost, String[] types,
|
||||||
// c.setManaCost(manaCost);
|
String[] intrinsicKeywords, int basePower, int baseToughness) {
|
||||||
c.addColor(manaCost);
|
this.name = name;
|
||||||
c.setToken(true);
|
this.imageName = imageName;
|
||||||
|
this.manaCost = manaCost;
|
||||||
for (final String t : types) {
|
this.types = types;
|
||||||
c.addType(t);
|
this.intrinsicKeywords = intrinsicKeywords;
|
||||||
|
this.basePower = basePower;
|
||||||
|
this.baseToughness = baseToughness;
|
||||||
}
|
}
|
||||||
|
|
||||||
c.setBasePower(basePower);
|
public TokenInfo(Card c) {
|
||||||
c.setBaseToughness(baseToughness);
|
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();
|
final int multiplier = controller.getTokenDoublersMagnitude();
|
||||||
for (int i = 0; i < multiplier; i++) {
|
for (int i = 0; i < multiplier; i++) {
|
||||||
Card temp = copyStats(c, controller);
|
Card temp = copyStats(c, controller);
|
||||||
|
|
||||||
for (final String kw : intrinsicKeywords) {
|
for (final String kw : tokenInfo.intrinsicKeywords) {
|
||||||
temp.addIntrinsicKeyword(kw);
|
temp.addIntrinsicKeyword(kw);
|
||||||
}
|
}
|
||||||
temp.setOwner(controller);
|
temp.setOwner(controller);
|
||||||
@@ -640,6 +729,7 @@ public class CardFactory {
|
|||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy triggered ability
|
* Copy triggered ability
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user