Card.getText()
Post MTG Forge Related Programming Questions Here
Moderators: timmermac, Blacksmith, KrazyTheFox, Agetian, friarsol, CCGHQ Admins
20 posts
• Page 1 of 2 • 1, 2
Card.getText()
by Chris H. » 12 Sep 2010, 13:05
I have recently spent some time in this section. We have a number of new keywords that were not showing up on Instants and Sorceries. I just added "CARDNAME is {color} for Ghostfire and Ancestral Vision. I also cleaned up and consolidated the code in this section.
I think that I am starting to understand why we have had this problem ever since Rob added the cantrip code. Instants and Sorceries have the spell abilities and the spellText combined but it had no code for adding keywords which do not create a spell ability with it's own spell ability description.
So things are a little bit better now but with the large number of new keywords added this summer it is possible that I may have overlooked a few. So the Card.getText() code for Instants and Sorceries now look like this:
I think that I am starting to understand why we have had this problem ever since Rob added the cantrip code. Instants and Sorceries have the spell abilities and the spellText combined but it had no code for adding keywords which do not create a spell ability with it's own spell ability description.
So things are a little bit better now but with the large number of new keywords added this summer it is possible that I may have overlooked a few. So the Card.getText() code for Instants and Sorceries now look like this:
- Code: Select all
public String getText() {
if(isInstant() || isSorcery()) {
String s = getSpellText();
StringBuilder sb = new StringBuilder();
// Give spellText line breaks for easier reading
sb.append(s.replaceAll("\\\\r\\\\n", "\r\n"));
// NOTE:
if (sb.toString().contains(" (NOTE: ")) {
sb.insert(sb.indexOf("(NOTE: "), "\r\n");
}
if (sb.toString().contains("(NOTE: ") && sb.toString().endsWith(".)") && !sb.toString().endsWith("\r\n")) {
sb.append("\r\n");
}
// Add SpellAbilities
SpellAbility[] sa = getSpellAbility();
for (int i = 0; i < sa.length; i++) {
sb.append(sa[i].toString() + "\r\n");
}
// Add Keywords
ArrayList<String> kw = getKeyword();
// Ripple + Dredge + Madness + CARDNAME is {color}.
for (int i = 0; i < kw.size(); i++) {
if ((kw.get(i).startsWith("Ripple") && !sb.toString().contains("Ripple"))
|| (kw.get(i).startsWith("Dredge") && !sb.toString().contains("Dredge"))
|| (kw.get(i).startsWith("Madness") && !sb.toString().contains("Madness"))
|| (kw.get(i).startsWith("CARDNAME is ") && !sb.toString().contains("CARDNAME is "))) {
sb.append(kw.get(i).replace(":", " ")).append("\r\n");
}
}
// Draw a card. + Changeling + CARDNAME can't be countered. + Cascade
for (int i = 0; i < kw.size(); i++) {
if ((kw.get(i).contains("Draw a card.") && !sb.toString().contains("Draw a card."))
|| (kw.get(i).contains("Changeling") && !sb.toString().contains("Changeling"))
|| (kw.get(i).contains("CARDNAME can't be countered.") && !sb.toString().contains("CARDNAME can't be countered."))
|| (kw.get(i).contains("Cascade") && !sb.toString().contains("Cascade"))) {
sb.append(kw.get(i)).append("\r\n");
}
}
// Storm
if (getKeyword().contains("Storm") && !sb.toString().contains("Storm (When you ")) {
if (sb.toString().endsWith("\r\n\r\n")) {
sb.delete(sb.lastIndexOf("\r\n"), sb.lastIndexOf("\r\n")+3);
}
sb.append("Storm (When you cast this spell, copy it for each spell cast before it this turn.");
if (sb.toString().contains("Target") || sb.toString().contains("target")) {
sb.append(" You may choose new targets for the copies.");
}
sb.append(")\r\n");
}
// Scry
if(!sb.toString().contains("Scry")) for(int i = 0; i < getKeyword().size(); i++) {
String k = getKeyword().get(i);
if(k.startsWith("Scry")) {
String kk[] = k.split(" ");
//sb.append("Scry " + kk[1] + " (To scry X, look at the top X cards of your library, then put any number of them on the bottom of your library and the rest on top in any order.)\r\n");
sb.append("Scry ");
sb.append(kk[1]);
sb.append(" (To scry X, look at the top X cards of your library, then put any number of them on the bottom of your library and the rest on top in any order.)\r\n");
}
}
while (sb.toString().endsWith("\r\n")) {
sb.delete(sb.lastIndexOf("\r\n"), sb.lastIndexOf("\r\n")+3);
}
return sb.toString().replaceAll("CARDNAME", getName());
}
-
Chris H. - Forge Moderator
- Posts: 6320
- Joined: 04 Nov 2008, 12:11
- Location: Mac OS X Yosemite
- Has thanked: 644 times
- Been thanked: 643 times
Re: Card.getText()
by Rob Cashwalker » 12 Sep 2010, 13:44
I'm sure this is on the top end of "best we can do now", but I also have a sneaking suspicion that it could be done cleaner, without including so much rules text that could be changed with any new set release when they revise oracle text.
Maybe we shouldn't try to use the spell descriptions for each spell ability. Instead, use the text field (now with line feeds!) for what it was intended. It's a field that the python script can maintain easily.
The spell description is only used for the multiple choice dialog.
Maybe we shouldn't try to use the spell descriptions for each spell ability. Instead, use the text field (now with line feeds!) for what it was intended. It's a field that the python script can maintain easily.
The spell description is only used for the multiple choice dialog.
The Force will be with you, Always.
-
Rob Cashwalker - Programmer
- Posts: 2167
- Joined: 09 Sep 2008, 15:09
- Location: New York
- Has thanked: 5 times
- Been thanked: 40 times
Re: Card.getText()
by Chris H. » 12 Sep 2010, 18:38
Yeah, I too have considered similar thoughts. The cards.txt file has gotten so large that it is hard to maintain it without conflicts arising. Imagine a folder with a separate text file for each and every cards. While we are it it we could have a label for each field. This would allow multi-line spell text descriptions without jumping through any additional hoops.
We can always dream.
We can always dream.
-
Chris H. - Forge Moderator
- Posts: 6320
- Joined: 04 Nov 2008, 12:11
- Location: Mac OS X Yosemite
- Has thanked: 644 times
- Been thanked: 643 times
Re: Card.getText()
by Rob Cashwalker » 13 Sep 2010, 00:45
I'm quickly warming up to that concept....
Short of figuring out how to iterate all files in a folder, I think I know for sure that by the next beta cards.txt will become a cards.folder.
Edit - I have this working!
This is ReadCard:
abandoned_outpost.txt: (filenames really don't matter)
Short of figuring out how to iterate all files in a folder, I think I know for sure that by the next beta cards.txt will become a cards.folder.
Edit - I have this working!
This is ReadCard:
- Code: Select all
package forge;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.StringTokenizer;
import forge.error.ErrorViewer;
import forge.properties.ForgeProps;
import forge.properties.NewConstants;
public class ReadCard implements Runnable, NewConstants {
private BufferedReader in;
private String fileList[];
private ArrayList<Card> allCards = new ArrayList<Card>();
public static void main(String args[]) throws Exception {
try {
ReadCard read = new ReadCard(ForgeProps.getFile(CARDS));
javax.swing.SwingUtilities.invokeAndWait(read);
// read.run();
Card c[] = new Card[read.allCards.size()];
read.allCards.toArray(c);
for(int i = 0; i < c.length; i++) {
System.out.println(c[i].getName());
System.out.println(c[i].getManaCost());
System.out.println(c[i].getType());
System.out.println(c[i].getSpellText());
System.out.println(c[i].getKeyword());
System.out.println(c[i].getBaseAttack() + "/" + c[i].getBaseDefense() + "\n");
}
} catch(Exception ex) {
ErrorViewer.showError(ex);
System.out.println("Error reading file " + ex);
}
}
public ArrayList<Card> getCards() {
return new ArrayList<Card>(allCards);
}
public ReadCard(String filename) {
this(new File(filename));
}
public ReadCard(File file) {
if(!file.exists())
throw new RuntimeException("ReadCard : constructor error -- file not found -- filename is "
+ file.getAbsolutePath());
if (!file.isDirectory())
throw new RuntimeException("ReadCard : constructor error -- not a direcotry -- "
+ file.getAbsolutePath());
fileList = file.list();
//makes the checked exception, into an unchecked runtime exception
//try {
// in = new BufferedReader(new FileReader(file));
//} catch(Exception ex) {
// ErrorViewer.showError(ex, "File \"%s\" not found", file.getAbsolutePath());
// throw new RuntimeException("ReadCard : constructor error -- file not found -- filename is "
// + file.getPath());
//}
}//ReadCard()
public void run() {
Card c = null;
ArrayList<String> cardNames = new ArrayList<String>();
File fl = null;
for (int i=0; i<fileList.length; i++)
{
try {
fl = new File("res/cardsfolder/" + fileList[i]);
in = new BufferedReader(new FileReader(fl));
} catch(Exception ex) {
ErrorViewer.showError(ex, "File \"%s\" exception", fl.getAbsolutePath());
throw new RuntimeException("ReadCard : run error -- file exception -- filename is "
+ fl.getPath());
}
c = new Card();
String s = readLine();
while (!s.equals("End"))
{
if (s.startsWith("Name:"))
{
String t = s.substring(5);
System.out.println(s);
if (cardNames.contains(t))
{
System.out.println("ReadCard:run() error - duplicate card name: " + t);
throw new RuntimeException("ReadCard:run() error - duplicate card name: " + t);
}
else
c.setName(t);
}
else if (s.startsWith("ManaCost:"))
{
String t = s.substring(9);
System.out.println(s);
if (!t.equals("no cost"))
c.setManaCost(t);
}
else if (s.startsWith("Types:"))
addTypes(c, s.substring(6));
else if (s.startsWith("Text:"))
{
String t = s.substring(5);
if (!t.equals("no text"));
c.setText(t);
}
else if (s.startsWith("PT:"))
{
String t = s.substring(3);
String pt[] = t.split("/");
int att = Integer.parseInt(pt[0]);
int def = Integer.parseInt(pt[1]);
c.setBaseAttack(att);
c.setBaseDefense(def);
}
else if (s.startsWith("K:"))
{
String t = s.substring(2);
c.addIntrinsicKeyword(t);
}
s = readLine();
} // while !End
cardNames.add(c.getName());
allCards.add(c);
try {
in.close();
} catch (IOException ex) {
ErrorViewer.showError(ex, "File \"%s\" exception", fl.getAbsolutePath());
throw new RuntimeException("ReadCard : run error -- file exception -- filename is "
+ fl.getPath());
}
}
}//run()
private void addTypes(Card c, String types) {
StringTokenizer tok = new StringTokenizer(types);
while(tok.hasMoreTokens())
c.addType(tok.nextToken());
}
private String readLine() {
//makes the checked exception, into an unchecked runtime exception
try {
String s = in.readLine();
if(s != null) s = s.trim();
return s;
} catch(Exception ex) {
ErrorViewer.showError(ex);
throw new RuntimeException("ReadCard : readLine(Card) error");
}
}//readLine(Card)
}
- Code: Select all
ReadCard read = new ReadCard(ForgeProps.getFile(CARDSFOLDER));
abandoned_outpost.txt: (filenames really don't matter)
- Code: Select all
Name:Abandoned Outpost
ManaCost:no cost
Types:Land
Text:no text
K:tap: add W
K:tap, Sacrifice CARDNAME: Add W to your mana pool.
K:tap, Sacrifice CARDNAME: Add U to your mana pool.
K:tap, Sacrifice CARDNAME: Add B to your mana pool.
K:tap, Sacrifice CARDNAME: Add R to your mana pool.
K:tap, Sacrifice CARDNAME: Add G to your mana pool.
K:Comes into play tapped.
K:SVar:Rarity:Common
K:SVar:Picture:http://www.wizards.com/global/images/magic/general/abandoned_outpost.jpg
End
- Code: Select all
Name:Abbey Gargoyles
ManaCost:2 W W W
Types:Creature Gargoyle
Text:no text
PT:3/4
K:Flying
K:Protection from red
K:SVar:Rarity:Uncommon
K:SVar:Picture:http://www.wizards.com/global/images/magic/general/abbey_gargoyles.jpg
End
The Force will be with you, Always.
-
Rob Cashwalker - Programmer
- Posts: 2167
- Joined: 09 Sep 2008, 15:09
- Location: New York
- Has thanked: 5 times
- Been thanked: 40 times
Re: Card.getText()
by Chris H. » 13 Sep 2010, 13:05
Wow. I am glad that I came back and took another look at your message.
The additional work that you appended onto the end of your message is awesome!
As far as file names I think you have the right idea. That system works well for the jpg pics and I can't think of any reasons why this should not be used.
Would Sol be able to write a python script to create the card files from the existing cards.txt file?
I guess that this would be a several step sort of process. Divide up the cards.txt file and add in your code. Bug test and fix any problems that come up.
Once things are stable we can then consider what it would take to replace all of the values included in the "Text:" field with the rules data at gathers. Comment out the code inside of Card.getText().
We may have some card and/or keyword code that would then have to be modified to handle the new system. The gather rules data would also need a little editing to add in the missing notes and we have the braces to remove.

As far as file names I think you have the right idea. That system works well for the jpg pics and I can't think of any reasons why this should not be used.
Would Sol be able to write a python script to create the card files from the existing cards.txt file?
I guess that this would be a several step sort of process. Divide up the cards.txt file and add in your code. Bug test and fix any problems that come up.
Once things are stable we can then consider what it would take to replace all of the values included in the "Text:" field with the rules data at gathers. Comment out the code inside of Card.getText().
We may have some card and/or keyword code that would then have to be modified to handle the new system. The gather rules data would also need a little editing to add in the missing notes and we have the braces to remove.
-
Chris H. - Forge Moderator
- Posts: 6320
- Joined: 04 Nov 2008, 12:11
- Location: Mac OS X Yosemite
- Has thanked: 644 times
- Been thanked: 643 times
Re: Card.getText()
by Rob Cashwalker » 13 Sep 2010, 13:54
I'm thinking I can actually re-hack the original ReadCard methods to make it spit out what we need...
Once it's broken out, it shouldn't be a huge change for the python script to maintain.
Once it's broken out, it shouldn't be a huge change for the python script to maintain.
The Force will be with you, Always.
-
Rob Cashwalker - Programmer
- Posts: 2167
- Joined: 09 Sep 2008, 15:09
- Location: New York
- Has thanked: 5 times
- Been thanked: 40 times
Re: Card.getText()
by Rob Cashwalker » 13 Sep 2010, 20:54
This is the output from hacking ReadCard to also dump it to individual card files.
The Force will be with you, Always.
-
Rob Cashwalker - Programmer
- Posts: 2167
- Joined: 09 Sep 2008, 15:09
- Location: New York
- Has thanked: 5 times
- Been thanked: 40 times
Re: Card.getText()
by Chris H. » 13 Sep 2010, 22:54
I downloaded the archive. Nice work. When should we make the change over?
-
Chris H. - Forge Moderator
- Posts: 6320
- Joined: 04 Nov 2008, 12:11
- Location: Mac OS X Yosemite
- Has thanked: 644 times
- Been thanked: 643 times
Re: Card.getText()
by Rob Cashwalker » 14 Sep 2010, 02:54
Well, I uploaded everything.
You changed Arashi, the Sky Asunder between the afternoon and evening, that will need to be re-applied.
You changed Arashi, the Sky Asunder between the afternoon and evening, that will need to be re-applied.
The Force will be with you, Always.
-
Rob Cashwalker - Programmer
- Posts: 2167
- Joined: 09 Sep 2008, 15:09
- Location: New York
- Has thanked: 5 times
- Been thanked: 40 times
Re: Card.getText()
by friarsol » 14 Sep 2010, 03:04
We should probably put a post up on the change so everyone is aware of the new format. And probably actually submit the new folder to the SVN. This will make mass-changes more difficult since devs can no longer just search through one file for a specific string.Rob Cashwalker wrote:Well, I uploaded everything.
You changed Arashi, the Sky Asunder between the afternoon and evening, that will need to be re-applied.
- friarsol
- Global Moderator
- Posts: 7593
- Joined: 15 May 2010, 04:20
- Has thanked: 243 times
- Been thanked: 965 times
Re: Card.getText()
by DennisBergkamp » 14 Sep 2010, 03:41
Yup, I don't see any of the individual card files committed....
-
DennisBergkamp - AI Programmer
- Posts: 2602
- Joined: 09 Sep 2008, 15:46
- Has thanked: 0 time
- Been thanked: 0 time
Re: Card.getText()
by Rob Cashwalker » 14 Sep 2010, 03:46
I selected all the card files and then did "Add to Version control". In fact, I did that before I committed the source code changes.
I just did a commit, see if that makes them show up.
I just did a commit, see if that makes them show up.
The Force will be with you, Always.
-
Rob Cashwalker - Programmer
- Posts: 2167
- Joined: 09 Sep 2008, 15:09
- Location: New York
- Has thanked: 5 times
- Been thanked: 40 times
-
DennisBergkamp - AI Programmer
- Posts: 2602
- Joined: 09 Sep 2008, 15:46
- Has thanked: 0 time
- Been thanked: 0 time
Re: Card.getText()
by Rob Cashwalker » 14 Sep 2010, 11:36
FYI - Google's SVN chokes on this many files.... And it seems like it doubles the data transmitted.
The Force will be with you, Always.
-
Rob Cashwalker - Programmer
- Posts: 2167
- Joined: 09 Sep 2008, 15:09
- Location: New York
- Has thanked: 5 times
- Been thanked: 40 times
Re: Card.getText()
by Chris H. » 14 Sep 2010, 12:43
`Rob Cashwalker wrote:Well, I uploaded everything.
You changed Arashi, the Sky Asunder between the afternoon and evening, that will need to be re-applied.
No problem, it was a simple replace "T:" with "tap:" change for readability. I can make this mod once the new card files are all in place.

-
Chris H. - Forge Moderator
- Posts: 6320
- Joined: 04 Nov 2008, 12:11
- Location: Mac OS X Yosemite
- Has thanked: 644 times
- Been thanked: 643 times
20 posts
• Page 1 of 2 • 1, 2
Who is online
Users browsing this forum: No registered users and 57 guests