View Javadoc

1   /*
2    *   Firemox is a turn based strategy simulator
3    *   Copyright (C) 2003-2007 Fabrice Daugan
4    *
5    *   This program is free software; you can redistribute it and/or modify it 
6    * under the terms of the GNU General Public License as published by the Free 
7    * Software Foundation; either version 2 of the License, or (at your option) any
8    * later version.
9    *
10   *   This program is distributed in the hope that it will be useful, but WITHOUT 
11   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12   * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more 
13   * details.
14   *
15   *   You should have received a copy of the GNU General Public License along  
16   * with this program; if not, write to the Free Software Foundation, Inc., 
17   * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18   */
19  package net.sf.firemox.xml.magic;
20  
21  import java.io.BufferedReader;
22  import java.io.File;
23  import java.io.FileNotFoundException;
24  import java.io.FileOutputStream;
25  import java.io.FileReader;
26  import java.io.IOException;
27  import java.io.PrintWriter;
28  import java.util.ArrayList;
29  import java.util.List;
30  
31  import javax.xml.XMLConstants;
32  
33  import net.sf.firemox.token.IdConst;
34  import net.sf.firemox.tools.MToolKit;
35  
36  import org.apache.commons.io.FileUtils;
37  import org.apache.commons.io.FilenameUtils;
38  import org.apache.commons.io.IOUtils;
39  import org.apache.commons.lang.StringUtils;
40  import org.kohsuke.args4j.CmdLineException;
41  import org.kohsuke.args4j.CmdLineParser;
42  
43  /***
44   * @author <a href="mailto:fabdouglas@users.sourceforge.net">Fabrice Daugan </a>
45   * @since 0.90
46   */
47  public final class Oracle2Xml {
48  
49  	/***
50  	 * May the validated cards (recycled directory) be patched by the new ones?
51  	 */
52  	private static final boolean UPDATE_CARD = false;
53  
54  	/***
55  	 * Bounds
56  	 */
57  	private static final int MAXI = Integer.MAX_VALUE;
58  
59  	private static final String TBS_NAME = IdConst.TBS_DEFAULT;
60  
61  	private static Options options;
62  
63  	/***
64  	 * Prevent this class to be instantiated.
65  	 */
66  	private Oracle2Xml() {
67  		super();
68  	}
69  
70  	/***
71  	 * @param oracleFile
72  	 *          the oracle format text file.
73  	 * @param destinationDir
74  	 *          the directory where built card will be placed.
75  	 * @param recycledDir
76  	 *          the directory where already built card are placed.
77  	 */
78  	@SuppressWarnings("null")
79  	public void serialize(File oracleFile, File destinationDir, File recycledDir) {
80  		if (!oracleFile.exists() || !oracleFile.isFile()) {
81  			System.err.println("The file '" + oracleFile + "' does not exist");
82  			System.exit(-1);
83  			return;
84  		}
85  
86  		if (!destinationDir.exists() || !destinationDir.isDirectory()) {
87  			System.err.println("The destination directory '" + destinationDir
88  					+ "' does not exist");
89  			System.exit(-1);
90  			return;
91  		}
92  		final StringBuilder cardText = new StringBuilder();
93  		int nbCard = 0;
94  		MToolKit.tbsName = TBS_NAME;
95  		try {
96  			final BufferedReader in = new BufferedReader(new FileReader(oracleFile));
97  			PrintWriter out = null;
98  			while (nbCard < MAXI) {
99  				String line = in.readLine();
100 				if (line == null)
101 					break;
102 				String cardName = line.trim();
103 				if (cardName.length() == 0) {
104 					continue;
105 				}
106 
107 				// a new card starts
108 				String fileName = MToolKit.getExactKeyName(cardName) + ".xml";
109 				if (new File(recycledDir, fileName).exists()) {
110 					if (UPDATE_CARD) {
111 						File patchFile = MToolKit.getFile("tbs/mtg/recycled/" + fileName);
112 						File tempFile = File.createTempFile(fileName, "temp");
113 						FileUtils.copyFile(patchFile, tempFile);
114 						final BufferedReader inExist = new BufferedReader(new FileReader(
115 								tempFile));
116 						final PrintWriter outExist = new PrintWriter(new FileOutputStream(
117 								patchFile));
118 						String lineExist = null;
119 						boolean found = false;
120 						while ((lineExist = inExist.readLine()) != null) {
121 							if (!found && lineExist.contains("name=\"")) {
122 								lineExist = lineExist
123 										.substring(0, lineExist.indexOf("name=\""))
124 										+ "name=\""
125 										+ cardName
126 										+ lineExist.substring(lineExist.indexOf("\"", lineExist
127 												.indexOf("name=\"")
128 												+ "name=\"".length() + 2));
129 								found = true;
130 							}
131 							outExist.println(lineExist);
132 						}
133 						IOUtils.closeQuietly(inExist);
134 						IOUtils.closeQuietly(outExist);
135 
136 						if (!found) {
137 							System.err.println(">> Error patching card '" + cardName + "'");
138 							// } else {
139 							// patching card
140 						}
141 					}
142 					skipCard(in);
143 					continue;
144 				}
145 
146 				out = new PrintWriter(new FileOutputStream(new File(destinationDir,
147 						fileName)));
148 				int[] manaCost = null;
149 
150 				// record the card text
151 				cardText.setLength(0);
152 				cardText.append("<!--\n\t");
153 
154 				List<String> properties = new ArrayList<String>();
155 				String power = null;
156 				String toughness = null;
157 				isNonBasicLand = false;
158 				isLocalEnchantCreature = false;
159 				isLocalEnchantLand = false;
160 				isLocalEnchantArtifact = false;
161 				isEnchantWorld = false;
162 				isLocalEnchantCreatureArtifact = false;
163 				isLocalEnchantPermanent = false;
164 				isLocalEnchantEnchantment = false;
165 				isGlobalEnchant = false;
166 				isInstant = false;
167 				isCreature = false;
168 				isArtifact = false;
169 				isSorcery = false;
170 				isSwamp = false;
171 				isIsland = false;
172 				isForest = false;
173 				isMountain = false;
174 				isPlains = false;
175 				boolean isTribal = false;
176 				boolean isPlaneswalker = false;
177 				boolean isEquipment = false;
178 
179 				line = in.readLine().trim().replaceAll("//(.*//)", "").toLowerCase();
180 				cardText.append('\t').append(line).append("\n");
181 
182 				isArtifact = line.indexOf("artifact") != -1;
183 				if (line.startsWith("land") || line.endsWith(" land")) {
184 					isNonBasicLand = true;
185 				} else {
186 					manaCost = extractManaCost(line);
187 					line = in.readLine().replaceAll("//(.*//)", "").toLowerCase();
188 					cardText.append('\t').append(line).append("\n");
189 					isLocalEnchantCreature = line.indexOf("enchant creature") != -1;
190 					isEnchantWorld = line.indexOf("world enchantment") != -1;
191 					isAura = line.indexOf("aura") != -1;
192 					isTribal = line.indexOf("tribal") != -1;
193 					isPlaneswalker = line.indexOf("planeswalker") != -1;
194 					if (line.indexOf("enchantment") != -1 && !isAura && !isEnchantWorld)
195 						isGlobalEnchant = true;
196 					if (!isGlobalEnchant && !isAura && !isEnchantWorld
197 							&& !isLocalEnchantCreature) {
198 						isInstant = line.indexOf("instant") != -1;
199 						isCreature = line.indexOf("creature") != -1;
200 						isSorcery = line.indexOf("sorcery") != -1;
201 						isSwamp = line.indexOf("swamp") != -1;
202 						isIsland = line.indexOf("island") != -1;
203 						isForest = line.indexOf("forest") != -1;
204 						isMountain = line.indexOf("mountain") != -1;
205 						isArtifact = isArtifact || line.indexOf("artifact") != -1;
206 						isPlains = line.indexOf("plains") != -1;
207 					}
208 				}
209 				if (line.indexOf("snow") != -1)
210 					properties.add("snow");
211 
212 				if (line.indexOf("legendary") != -1)
213 					properties.add("legend");
214 
215 				if (line.indexOf("-") != -1) {
216 					properties = extractProperties(line.substring(line.indexOf("-") + 1)
217 							.trim(), properties);
218 				}
219 				if (isCreature) {
220 					line = in.readLine();
221 					cardText.append('\t').append(line).append("\n");
222 					if (line.indexOf("/") == -1) {
223 						System.err.println("Error reading card '" + cardName
224 								+ "' : power/toughness, line=" + line);
225 						skipCard(in);
226 						continue;
227 					}
228 					power = line.substring(0, line.indexOf('/')).trim();
229 					toughness = line.substring(line.indexOf('/') + 1).trim();
230 				}
231 				if (isEnchantWorld) {
232 					properties.add("enchant-world");
233 				}
234 
235 				if (properties.contains("equipment"))
236 					isEquipment = true;
237 
238 				List<String> lineBuffer = new ArrayList<String>();
239 				boolean hasBuyBack = false;
240 				boolean hasFlashBack = false;
241 				boolean hasForecast = false;
242 				boolean hasAffinity = false;
243 				boolean hasRampage = false;
244 				boolean hasTransmute = false;
245 				boolean hasDredge = false;
246 				boolean hasHaunt = false;
247 				boolean hasBloodThirst = false;
248 				boolean hasBushido = false;
249 				String hasTransmuteCost = null;
250 				int hasRampageCount = 1;
251 				int hasDredgeCount = 1;
252 				int hasBloodThirstCount = 1;
253 				int hasBushidoCount = 1;
254 				boolean hasFading = false;
255 				boolean hasLessToPlay = false;
256 				boolean hasMoreToPlay = false;
257 				boolean hasVanishing = false;
258 				lowerCard = cardName.toLowerCase();
259 				String hasBuyBackLine = null;
260 				String hasFlashBackLine = null;
261 				String hasAffinityLine = null;
262 				String hasForecastLine = null;
263 				String hasFadingLine = null;
264 				String hasVanishingLine = null;
265 				String hasSuspendLine = null;
266 				boolean hasFlanking = false;
267 				boolean hasHaunting = false;
268 				boolean hasSuspend = false;
269 				boolean hasLifelink = false;
270 				boolean hasDeathtouch = false;
271 
272 				String equipLine = "";
273 
274 				while (true) {
275 					line = in.readLine();
276 					if (line == null || line.length() == 0)
277 						break;
278 					line = line.replaceAll("T ", "T :").replaceAll("//(.*//)", "")
279 							.toLowerCase();
280 					cardText.append('\t').append(line).append('\n');
281 
282 					if (isAura && !isLocalEnchantCreature && !isLocalEnchantLand
283 							&& !isLocalEnchantCreatureArtifact && !isLocalEnchantArtifact
284 							&& !isLocalEnchantPermanent && !isLocalEnchantEnchantment) {
285 						isLocalEnchantCreature = line.indexOf("enchant creature") != -1;
286 						isLocalEnchantLand = line.indexOf("enchant land") != -1;
287 						isLocalEnchantCreatureArtifact = line
288 								.indexOf("enchant artifact creature") != -1;
289 						isLocalEnchantArtifact = !isLocalEnchantCreatureArtifact
290 								&& line.indexOf("enchant artifact") != -1;
291 						isLocalEnchantPermanent = line.indexOf("enchant permanent") != -1;
292 						isLocalEnchantEnchantment = line.indexOf("enchant enchantment") != -1;
293 					}
294 
295 					if (line.startsWith("buyback")) {
296 						hasBuyBack = true;
297 						hasBuyBackLine = line.substring("buyback".length()).trim();
298 						continue;
299 					} else if (line.startsWith("haunt")) {
300 						hasHaunt = true;
301 						continue;
302 					} else if (line.startsWith("flashback")) {
303 						hasFlashBack = true;
304 						hasFlashBackLine = line.substring("flashback".length()).trim();
305 						continue;
306 					} else if (line.startsWith("affinity for ")) {
307 						hasAffinity = true;
308 						hasAffinityLine = line.substring("affinity for ".length()).trim();
309 						continue;
310 					} else if (line.startsWith("forecast")) {
311 						hasForecast = true;
312 						hasForecastLine = line.substring("forecast - ".length()).trim();
313 						continue;
314 					} else if (line.startsWith("rampage ")) {
315 						hasRampage = true;
316 						hasRampageCount = Integer.parseInt(line.substring(
317 								"rampage ".length(), "rampage ".length() + 1).trim());
318 						continue;
319 					} else if (line.startsWith("transmute ")) {
320 						hasTransmute = true;
321 						hasTransmuteCost = line.substring("transmute ".length()).trim();
322 						continue;
323 					} else if (line.startsWith("dredge ")) {
324 						hasDredge = true;
325 						hasDredgeCount = Integer.parseInt(line.substring(
326 								"dredge ".length(), "dredge ".length() + 1).trim());
327 						continue;
328 					} else if (line.startsWith("bloodthirst ")) {
329 						hasBloodThirst = true;
330 						String bloodThirst = line.substring("bloodthirst ".length(),
331 								"bloodthirst ".length() + 1).trim();
332 						if (bloodThirst.compareTo("x") != 0)
333 							hasBloodThirstCount = Integer.parseInt(bloodThirst);
334 						else
335 							hasBloodThirstCount = 0; // 0 must be changed to a variable that
336 						// counts damage opponent has taken the present turn
337 						continue;
338 					} else if (line.startsWith("bushido ")) {
339 						hasBushido = true;
340 						hasBushidoCount = Integer.parseInt(line.substring(
341 								"bushido ".length(), "bushido ".length() + 1).trim());
342 						continue;
343 					} else if (line.startsWith("fading")) {
344 						hasFading = true;
345 						hasFadingLine = line.substring("fading".length()).trim();
346 						continue;
347 					} else if (line.startsWith("vanishing")) {
348 						hasVanishing = true;
349 						hasVanishingLine = line.substring("vanishing".length()).trim();
350 						continue;
351 					} else if (line.startsWith("flanking")) {
352 						hasFlanking = true;
353 						continue;
354 					} else if (line.startsWith("haunt")) {
355 						hasHaunting = true;
356 						continue;
357 					} else if (line.startsWith("suspend")) {
358 						hasSuspend = true;
359 						hasSuspendLine = line.substring("suspend ".length()).trim();
360 						continue;
361 					}
362 					if (line.contains(" less to play.")) {
363 						hasLessToPlay = true;
364 					}
365 					if (line.contains(" more to play.")) {
366 						hasMoreToPlay = true;
367 					}
368 					if (line.contains("lifelink")) {
369 						hasLifelink = true;
370 					}
371 					if (line.contains("deathtouch")) {
372 						hasDeathtouch = true;
373 					}
374 
375 					if (line.indexOf(lowerCard + " doesn't untap during") != -1) {
376 						properties.add("does-not-untap");
377 					}
378 					if (line.indexOf("you may choose not to untap") != -1) {
379 						properties.add("may-not-untap");
380 					}
381 					if (line.indexOf(lowerCard + " can't block") != -1) {
382 						properties.add("cannot-block");
383 					}
384 					if (line.indexOf(lowerCard + " can't attack") != -1) {
385 						properties.add("cannot-attack");
386 					}
387 					if (line.indexOf(lowerCard + " is unblockable.") != -1)
388 						properties.add("unblockable");
389 
390 					if (line.indexOf(lowerCard + " is indestructible.") != -1)
391 						properties.add("indestructible");
392 
393 					if (line.indexOf(lowerCard + " can't be countered.") != -1)
394 						properties.add("cannot-be-countered");
395 
396 					if (line.indexOf(lowerCard + " attacks each turn if able.") != -1)
397 						properties.add("attacks-if-able");
398 
399 					if (line.indexOf(lowerCard + " can't be blocked by walls.") != -1)
400 						properties.add("cannot-be-blocked-by-walls");
401 
402 					if (line.indexOf(lowerCard + " can block only creatures with flying") != -1)
403 						properties.add("block-only-flying");
404 
405 					line = updateProperties(line, properties);
406 					lineBuffer.add(line);
407 				}
408 
409 				cardText.append(" -->");
410 				out.println("<?xml version='1.0'?>");
411 
412 				out.print("<card xmlns='");
413 				out.println(IdConst.NAME_SPACE + "'");
414 				out.print("\txmlns:xsi='");
415 				out.print(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI);
416 				out.println("'");
417 				out.print("\txsi:schemaLocation='");
418 				out.println(IdConst.NAME_SPACE + " ../../" + IdConst.TBS_XSD + "'");
419 				out.println("\tname=\"" + cardName + "\">");
420 				out.println("<rules-author-comment>Oracle2Xml generator "
421 						+ IdConst.VERSION + "</rules-author-comment>\n");
422 				out.println(cardText.toString());
423 				out.println("\n\t<!-- COMPLETE THE CODE OF THIS CARD -->\n");
424 				out.println("\t<init>");
425 				out.println("\t\t<registers>");
426 				if (manaCost != null) {
427 					for (int i = 6; i-- > 0;) {
428 						if (manaCost[i] > 0) {
429 							out.println("\t\t\t<register index='" + extractColor(i)
430 									+ "' value='" + manaCost[i] + "'/>");
431 						}
432 					}
433 				}
434 				// power / toughness
435 				if (isCreature) {
436 					if (power.indexOf("*") != -1) {
437 						// power depends on ...
438 						out.println("\t\t\t<register index='power'>");
439 						out.println("\t\t\t\t<!-- REPLACE THIS CODE -->");
440 						out.println("\t\t\t\t<value><counter restriction-zone='play'>");
441 						out.println("\t\t\t\t\t<and>");
442 						out.println("\t\t\t\t\t\t<has-idcard idcard='swamp'/>");
443 						out.println("\t\t\t\t\t\t<controller player='you'/>");
444 						out.println("\t\t\t\t\t</and>");
445 						out.println("\t\t\t\t</counter></value>");
446 						out.println("\t\t\t</register>");
447 					} else {
448 						out
449 								.println("\t\t\t<register index='power' value='" + power
450 										+ "'/>");
451 					}
452 					if (toughness.indexOf("*") != -1) {
453 						// toughness depends on ...
454 						out.println("\t\t\t<register index='toughness'>");
455 						out.println("\t\t\t\t<!-- REPLACE THIS CODE -->");
456 						out.println("\t\t\t\t<value><counter restriction-zone='play'>");
457 						out.println("\t\t\t\t\t<and>");
458 						out.println("\t\t\t\t\t\t<has-idcard idcard='swamp'/>");
459 						out.println("\t\t\t\t\t\t<controller player='you'/>");
460 						out.println("\t\t\t\t\t</and>");
461 						out.println("\t\t\t\t</counter></value>");
462 						out.println("\t\t\t</register>");
463 					} else {
464 						out.println("\t\t\t<register index='toughness' value='" + toughness
465 								+ "'/>");
466 					}
467 				}
468 				out.println("\t\t</registers>");
469 
470 				// colors
471 				if (manaCost != null && manaCost.length > 0) {
472 					out.print("\t\t<colors>");
473 					for (int i = manaCost.length - 1; i-- > 1;) {
474 						if (manaCost[i] > 0) {
475 							out.print(extractColor(i));
476 							if (i > 0) {
477 								out.print(" ");
478 							}
479 						}
480 					}
481 					out.println("</colors>");
482 				}
483 
484 				// idcards
485 				out.print("\t\t<idcards>");
486 				if (isTribal)
487 					out.print("tribal ");
488 				if (isPlaneswalker)
489 					out.print("planeswalker ");
490 				else if (isCreature && isArtifact) {
491 					out.print("artifact-creature ");
492 				} else if (isArtifact)
493 					out.print("artifact ");
494 				else if (isCreature)
495 					out.print("creature ");
496 				if (isNonBasicLand) {
497 					out.print("land ");
498 				} else if (isAura) {
499 					out.print("local-enchantment ");
500 				} else if (isEnchantWorld) {
501 					out.print("enchant-world ");
502 				} else if (isGlobalEnchant) {
503 					out.print("global-enchantment ");
504 				} else if (isInstant) {
505 					out.print("instant ");
506 				} else if (isSorcery) {
507 					out.print("sorcery ");
508 				}
509 				if (isSwamp) {
510 					out.print("swamp ");
511 				}
512 				if (isIsland) {
513 					out.print("island ");
514 				}
515 				if (isForest) {
516 					out.print("forest ");
517 				}
518 				if (isMountain) {
519 					out.print("mountain ");
520 				}
521 				if (isPlains) {
522 					out.print("plains ");
523 				}
524 				out.println("</idcards>");
525 
526 				// properties
527 				if (!properties.isEmpty()) {
528 					out.print("\t\t<properties>");
529 					for (String property : properties) {
530 						out.print(property);
531 						out.print(" ");
532 					}
533 					out.println("</properties>");
534 				}
535 				out.println("\t</init>");
536 
537 				if (!lineBuffer.isEmpty()) {
538 					line = lineBuffer.get(0);
539 				}
540 				if (hasFlashBack) {
541 					out.println("\t<actions>");
542 					out.println("\t\t<action reference-name='main-effects'>");
543 					/*
544 					 * if (line.indexOf(':') != -1) { writeActions(out,
545 					 * line.substring(line.indexOf(':') + 1), true); }
546 					 */
547 					writeActions(out, line, true, false);
548 					out
549 							.println("\t\t\t\t<!-- PUT HERE EFFECTS OF THIS SPELL. THIS WILL BE INCLUDED TO FLASHBACK TOO -->");
550 					out.println("\t\t</action>");
551 					out.println("\t</actions>");
552 				}
553 
554 				// abilities
555 				out.println("\t<abilities>");
556 
557 				if (hasLifelink)
558 					out.println("\t\t<ability ref='lifelink'/>");
559 
560 				if (hasDeathtouch)
561 					out.println("\t\t<ability ref='deathtouch'/>");
562 
563 				if (hasSuspend) {
564 					out.println("\t\t<ability ref='cast-suspend'>");
565 					out.println("\t\t\t<actions>");
566 					writeCost(out, hasSuspendLine
567 							.substring(hasSuspendLine.indexOf("-") + 1), null);
568 					out.println("\t\t\t</actions>");
569 					out.println("\t\t\t<actions>");
570 					out.println("\t\t\t\t<repeat value='" + hasSuspendLine.charAt(0)
571 							+ "'/>");
572 					out.println("\t\t\t\t<add-object object-name='time'/>");
573 					out.println("\t\t\t</actions>");
574 					out.println("\t\t</ability>");
575 				}
576 
577 				if (isAura) {
578 					out.println("\t\t<ability ref='cast-enchant'/>");
579 				} else if (isCreature || isGlobalEnchant || isArtifact
580 						|| isPlaneswalker) {
581 					if (hasAffinity) {
582 						out.println("\t\t<ability ref='cast-spell'>");
583 						out.println("\t\t\t<actions>");
584 						writeAffinity(out, hasAffinityLine);
585 						out.println("\t\t\t</actions>");
586 						out.println("\t\t</ability>");
587 					} else {
588 						out.println("\t\t<ability ref='cast-spell'/>");
589 					}
590 				} else if (isNonBasicLand || isForest || isPlains || isIsland
591 						|| isSwamp || isMountain) {
592 					out.println("\t\t<ability ref='cast-land'/>");
593 				}
594 
595 				if (hasForecast) {
596 					out.println("\t\t<ability ref='reset-forecast' />");
597 					out.println("\t\t<ability ref='forecast'>");
598 					out.println("\t\t\t<actions>");
599 					writeCost(out, hasForecastLine, null);
600 					out.println("\t\t\t</actions>");
601 					out.println("\t\t\t<actions>");
602 					out.println("\t\t\t\t<!-- PUT HERE THE EFFECTS OF FORECAST -->");
603 					out.println("\t\t\t</actions>");
604 					out.println("\t\t</ability>");
605 				}
606 
607 				if (isInstant || isSorcery) {
608 					out.println("\t\t<activated-ability "
609 							+ (hasBuyBack || hasFlashBack ? "reference-name='main-ability' "
610 									: "") + "playable='this' name='' zone='hand'>");
611 					out.println("\t\t\t<cost>");
612 					out.println("\t\t\t\t<pay-mana value='manacost'/>");
613 					if (hasAffinity)
614 						writeAffinity(out, hasAffinityLine);
615 					writeXmanaCost(out, manaCost, false);
616 					if (hasFlashBack) {
617 						out
618 								.println("\t\t\t\t<!-- PUT HERE THE COST OF THIS SPELL. THIS WILL NOT BE INCLUDED TO FLASHBACK COST -->");
619 						out.println("\t\t\t</cost>");
620 						out.println("\t\t\t<effects>");
621 						out.println("\t\t\t\t<action ref='main-effects'/>");
622 						out.println("\t\t\t\t<action ref='finish-spell'/>");
623 
624 					} else {
625 						if (line.indexOf("at the beginning of") != -1) {
626 							out.println("\t\t<create-ability>");
627 							out
628 									.println("\t\t\t<!-- UPDATE PHASE NAME, TYPE and RESOLUTION -->");
629 							out
630 									.println("\t\t\t<triggered-ability resolution='normal' zone='play'>");
631 							out.println("\t\t\t\t<beginning-of-phase phase='upkeep'>");
632 							out.println("\t\t\t\t\t<test ref='during-your-upkeep'/>");
633 							out.println("\t\t\t\t</beginning-of-phase>");
634 							out.println("\t\t\t\t<effects>");
635 							writeActions(out, line, true, false);
636 							out
637 									.println("\t\t\t\t\t<!-- PUT HERE EFFECTS OF THIS DELAYED CARD -->");
638 							out.println("\t\t\t\t\t<unregister-this/>");
639 							out.println("\t\t\t\t</effects>");
640 							out.println("\t\t\t</triggered-ability>");
641 							out.println("\t\t</create-ability>");
642 						}
643 						if (line.indexOf(':') != -1) {
644 							writeActions(out, line.substring(0, line.indexOf(':')), true,
645 									false);
646 						} else {
647 							line = writeCost(out, "", line);
648 						}
649 						if (line.indexOf("as an additional cost to play " + lowerCard) != -1) {
650 							writeActions(out, line
651 									.substring(("as an additional cost to play " + lowerCard)
652 											.length()), true, false);
653 							line = "";
654 						}
655 						out.println("\t\t\t\t<!-- PUT HERE THE COST OF THIS SPELL -->");
656 						out.println("\t\t\t</cost>");
657 						out.println("\t\t\t<effects>");
658 						for (String subLine : lineBuffer) {
659 							writeActions(out, subLine, false, false);
660 						}
661 						out.println("\t\t\t\t<!-- PUT HERE EFFECTS OF THIS SPELL -->");
662 						out.println("\t\t\t\t<action ref='finish-spell'/>");
663 					}
664 					out.println("\t\t\t</effects>");
665 					out.println("\t\t</activated-ability>");
666 				}
667 
668 				// Rampage
669 				if (hasRampage) {
670 					out.println("\t\t<ability ref='rampage" + hasRampageCount + "'/>");
671 				}
672 
673 				// Transmute
674 				if (hasTransmute) {
675 					out.println("\t\t<ability ref='transmute'>");
676 					out.println("\t\t\t<actions>");
677 					writeCost(out, hasTransmuteCost, null);
678 					out.println("\t\t\t</actions>");
679 					out.println("\t\t</ability>");
680 				}
681 
682 				// Dredge
683 				if (hasDredge) {
684 					out.println("\t\t<ability ref='dredge" + hasDredgeCount + "'/>");
685 				}
686 
687 				// Haunt
688 				if (hasHaunt) {
689 					out.println("\t\t<ability ref='haunting'/>");
690 				}
691 
692 				// BloodThirst
693 				if (hasBloodThirst) {
694 					out.println("\t\t<ability ref='bloodthirst" + hasBloodThirstCount
695 							+ "'/>");
696 				}
697 
698 				// Bushido
699 				if (hasBushido) {
700 					out.println("\t\t<ability ref='bushido" + hasBushidoCount
701 							+ "-blocked'/>");
702 					out.println("\t\t<ability ref='bushido" + hasBushidoCount
703 							+ "-blocking'/>");
704 				}
705 
706 				// Buyback
707 				if (hasBuyBack) {
708 					line = hasBuyBackLine;
709 					out
710 							.println("\t\t<activated-ability playable='this' name='buyback%a' zone='hand'>");
711 					out.println("\t\t\t<cost>");
712 					out.println("\t\t\t\t<action ref='buyback'/>");
713 					writeCost(out, line, null);
714 					out
715 							.println("\t\t\t\t<!-- PUT HERE THE COST OF BUYBACK, AND COMPLETE THE MAIN ABILITY OF THE SPELL -->");
716 					out.println("\t\t\t\t<insert-ability ref='main-ability'/>");
717 					out.println("\t\t\t</cost>");
718 					out.println("\t\t</activated-ability>");
719 				}
720 
721 				// Flashback
722 				if (hasFlashBack) {
723 					line = hasFlashBackLine;
724 					out
725 							.println("\t\t<activated-ability playable='this' name='flashback%a' zone='graveyard'>");
726 					out.println("\t\t\t<cost>");
727 					writeCost(out, line, null);
728 					out
729 							.println("\t\t\t\t<!-- PUT HERE THE COST OF FLASHBACK, AND COMPLETE THE MAIN ABILITY OF THE SPELL -->");
730 					out.println("\t\t\t</cost>");
731 					out.println("\t\t\t<effects>");
732 					out.println("\t\t\t\t<action ref='main-effects'/>");
733 					out.println("\t\t\t\t<action ref='flashback'/>");
734 					out.println("\t\t\t</effects>");
735 					out.println("\t\t</activated-ability>");
736 				}
737 
738 				// Flanking
739 				if (hasFlanking) {
740 					out.println("\t\t<ability ref='flanking'/>");
741 				}
742 
743 				// Haunting
744 				if (hasHaunting) {
745 					out.println("\t\t<ability ref='haunting'/>");
746 				}
747 
748 				// Fading
749 				if (hasFading) {
750 					out.println("\t\t<ability ref='fading'/>");
751 				}
752 
753 				// Vanishing
754 				if (hasVanishing) {
755 					out.println("\t\t<ability ref='vanishing'/>");
756 				}
757 
758 				for (int k = 0; k < lineBuffer.size(); k++) {
759 					line = lineBuffer.get(k);
760 
761 					// Equipment
762 					if (line.contains("equipped creature gets"))
763 						equipLine = line.substring(line.indexOf("gets ") + "gets ".length()
764 								+ 1);
765 
766 					if (line.indexOf("equip ") != -1 && isEquipment) {
767 
768 						out.println("\t\t<activated-ability playable='this' zone='play'>");
769 						out.println("\t\t\t<cost>");
770 						writeCost(out, line.substring("equip".length()), null);
771 						out.println("\t\t\t\t<action ref='target-equipable-creature' />");
772 						out.println("\t\t\t</cost>");
773 						out.println("\t\t\t<effects>");
774 						out.println("\t\t\t\t<action ref='equip' />");
775 						out.println("\t\t\t</effects>");
776 						out.println("\t\t</activated-ability>");
777 					}
778 
779 					// morph
780 					boolean hasMorph = false;
781 
782 					if (line.indexOf("morph") == 0) {
783 						hasMorph = true;
784 						out.println("\t\t<ability ref='cast-morph'/>");
785 						out.println("\t\t<ability ref='morph'>");
786 						out.println("\t\t\t<actions>");
787 						writeCost(out, line.substring("morph".length()), null);
788 						out.println("\t\t\t</actions>");
789 						out.println("\t\t</ability>");
790 					}
791 
792 					if (line.indexOf(lowerCard + " comes into play tapped") != -1) {
793 						out.println("\t\t<ability ref='come-into-play-tapped'/>");
794 					}
795 
796 					if (!isInstant && !isSorcery && line.length() > 0
797 							&& line.indexOf(':') != -1) {
798 						// activated abilities
799 						out
800 								.println("\t\t<activated-ability playable='instant' name='' zone='play'>");
801 
802 						// test part
803 						if (hasMorph) {
804 							out.println("\t\t\t<test>");
805 							out.println("\t\t\t\t<is-faceup card=\"me\"/>");
806 							out.println("\t\t\t</test>");
807 						}
808 
809 						// 1) cost part
810 						out.println("\t\t\t<cost>");
811 						out.println("\t\t\t\t<!-- PUT HERE THE COST OF THIS ABILITY -->");
812 						writeCost(out, line.substring(0, line.indexOf(':')), line
813 								.substring(line.indexOf(':') + 1));
814 						writeActions(out, line.substring(0, line.indexOf(':')), true, true);
815 						if (line.contains("play this ability only once each turn"))
816 							out.println("\t\t\t\t<action ref='use-once-each-turn'/>");
817 						out.println("\t\t\t</cost>");
818 
819 						// 2) effect part
820 						out.println("\t\t\t<effects>");
821 						out.println("\t\t\t\t<!-- PUT HERE EFFECTS OF THIS ABILITY -->");
822 						if (line.indexOf(":") != -1) {
823 							writeActions(out, line.substring(line.indexOf(':') + 1), false,
824 									false);
825 						} else {
826 							writeActions(out, line, false, false);
827 						}
828 						out.println("\t\t\t</effects>");
829 						out.println("\t\t</activated-ability>");
830 					}
831 
832 					if (line.indexOf("when") != -1 || line.indexOf("whenever") != -1) {
833 						if (line.indexOf("comes into play") != -1) {
834 							out.println("\t\t<triggered-ability zone='play'>");
835 							out.println("\t\t\t<moved-card>");
836 							out.println("\t\t\t\t<source-test>");
837 							if (line.indexOf("when " + lowerCard + " comes into play") != -1) {
838 								out.println("\t\t\t\t\t<and>");
839 								out.println("\t\t\t\t\t\t<is-this/>");
840 								out.println("\t\t\t\t\t\t<not>");
841 								out
842 										.println("\t\t\t\t\t\t\t<in-zone zone='play' card='tested'/>");
843 								out.println("\t\t\t\t\t\t</not>");
844 								out
845 										.println("\t\t\t\t\t\t<!-- PUT HERE ADDITIONAL TEST ON CARD BEFORE IT GOES TO PLAY -->");
846 								out.println("\t\t\t\t\t</and>");
847 							} else {
848 								out
849 										.println("\t\t\t\t<!-- PUT HERE ADDITIONAL TEST ON CARD BEFORE IT GOES TO PLAY -->");
850 							}
851 							out.println("\t\t\t\t</source-test>");
852 							out.println("\t\t\t\t<destination-test>");
853 							out
854 									.println("\t\t\t\t\t<!-- PUT HERE ADDITIONAL TEST ON CARD WHEN IT GOES TO PLAY -->");
855 							out.println("\t\t\t\t\t<in-zone zone='play' card='tested'/>");
856 							out.println("\t\t\t\t</destination-test>");
857 							out.println("\t\t\t</moved-card>");
858 						} else if (line.indexOf(" is put into ") < line
859 								.indexOf("graveyard from ")) {
860 							out.println("\t\t<triggered-ability zone='graveyard'>");
861 							out.println("\t\t\t<moved-card>");
862 							out.println("\t\t\t\t<source-test>");
863 							out
864 									.println("\t\t\t\t\t<!-- UPDATE TEST ON CARD BEFORE IT GOES TO GRAVEYARD -->");
865 							out.println("\t\t\t\t\t<and>");
866 							out.println("\t\t\t\t\t\t<is-this/>");
867 							out.println("\t\t\t\t\t\t<in-zone zone='play' card='tested'/>");
868 							out.println("\t\t\t\t\t</and>");
869 							out.println("\t\t\t\t</source-test>");
870 							out.println("\t\t\t\t<destination-test>");
871 							out
872 									.println("\t\t\t\t\t<!-- PUT HERE ADDITIONAL TEST ON CARD WHEN IT GOES TO GRAVEYARD -->");
873 							out
874 									.println("\t\t\t\t\t<in-zone zone='graveyard' card='tested'/>");
875 							out.println("\t\t\t\t</destination-test>");
876 							out.println("\t\t\t</moved-card>");
877 						} else if (line.indexOf(" leaves play") != -1) {
878 							out.println("\t\t<triggered-ability zone='graveyard'>");
879 							out.println("\t\t\t<moved-card>");
880 							out.println("\t\t\t\t<source-test>");
881 							out
882 									.println("\t\t\t\t\t<!-- COMPLETE TEST ON CARD BEFORE IT LEAVE PLAY -->");
883 							out.println("\t\t\t\t\t\t\t<in-zone zone='play' card='tested'/>");
884 							out.println("\t\t\t\t</source-test>");
885 							out.println("\t\t\t</moved-card>");
886 						} else if (line.indexOf("blocks") != -1
887 								|| line.indexOf("becomes blocked") != -1) {
888 							out.println("\t\t<triggered-ability zone='play'>");
889 							out.println("\t\t\t<declared-blocking>");
890 							out.println("\t\t\t\t<blocking-test>");
891 							out
892 									.println("\t\t\t\t\t<!-- COMPLETE THE TEST APPLIED ON BLOCKING CREATURE -->");
893 							out.println("\t\t\t\t</blocking-test>");
894 							out.println("\t\t\t\t<attacking-test>");
895 							out
896 									.println("\t\t\t\t\t<!-- COMPLETE THE TEST APPLIED ON ATTACKING CREATURE -->");
897 							out.println("\t\t\t\t</attacking-test>");
898 							out.println("\t\t\t</declared-blocking>");
899 						} else if (line.indexOf("attacks and isn't blocked") != -1) {
900 							out.println("\t\t<triggered-ability zone='play'>");
901 							out
902 									.println("\t\t\t<modified-register operation='or' register='card' index='state'>");
903 							out.println("\t\t\t\t<source-test>");
904 							out
905 									.println("\t\t\t\t\t<!-- COMPLETE THE TEST APPLIED ON UNBLOCKED CREATURE -->");
906 							out.println("\t\t\t\t\t<is-this/>");
907 							out.println("\t\t\t\t</source-test>");
908 							out.println("\t\t\t</modified-register>");
909 						} else if (line.indexOf("deals combat damage to a player") != -1) {
910 							out.println("\t\t<triggered-ability zone='play'>");
911 							out.println("\t\t\t<assigned-damage type='damage-combat'>");
912 							out.println("\t\t\t\t<source-test>");
913 							out.println("\t\t\t\t\t<is-this/>");
914 							out.println("\t\t\t\t</source-test>");
915 							out.println("\t\t\t\t<destination-test>");
916 							out.println("\t\t\t\t\t<is-player/>");
917 							out.println("\t\t\t\t</destination-test>");
918 							out.println("\t\t\t</assigned-damage>");
919 						} else if (line.indexOf("deals damage to") != -1) {
920 							out.println("\t\t<triggered-ability zone='play'>");
921 							out.println("\t\t\t<assigned-damage type='damage-any'>");
922 							out.println("\t\t\t\t<source-test>");
923 							out.println("\t\t\t\t\t<is-this/>");
924 							out.println("\t\t\t\t</source-test>");
925 							out.println("\t\t\t\t<destination-test>");
926 							out.println("\t\t\t\t\t<and>");
927 							out.println("\t\t\t\t\t\t<not>");
928 							out.println("\t\t\t\t\t\t<is-player/>");
929 							out.println("\t\t\t\t\t\t</not>");
930 							out.println("\t\t\t\t\t\t<has-idcard idcard='creature'/>");
931 							out.println("\t\t\t\t\t</and>");
932 							out.println("\t\t\t\t</destination-test>");
933 							out.println("\t\t\t</assigned-damage>");
934 						} else if (line.indexOf("deals combat damage to") != -1) {
935 							out.println("\t\t<triggered-ability zone='play'>");
936 							out.println("\t\t\t<assigned-damage type='damage-combat'>");
937 							out.println("\t\t\t\t<source-test>");
938 							out.println("\t\t\t\t\t<is-this/>");
939 							out.println("\t\t\t\t</source-test>");
940 							out.println("\t\t\t\t<destination-test>");
941 							out.println("\t\t\t\t\t<and>");
942 							out.println("\t\t\t\t\t\t<not>");
943 							out.println("\t\t\t\t\t\t\t<is-player/>");
944 							out.println("\t\t\t\t\t\t</not>");
945 							out.println("\t\t\t\t\t\t<has-idcard idcard='creature'/>");
946 							out.println("\t\t\t\t\t</and>");
947 							out.println("\t\t\t\t</destination-test>");
948 							out.println("\t\t\t</assigned-damage>");
949 						} else if (line.indexOf("deals damage to a player") != -1) {
950 							out.println("\t\t<triggered-ability zone='play'>");
951 							out.println("\t\t\t<assigned-damage type='damage-any'>");
952 							out.println("\t\t\t\t<source-test>");
953 							out.println("\t\t\t\t\t<is-this/>");
954 							out.println("\t\t\t\t</source-test>");
955 							out.println("\t\t\t\t<destination-test>");
956 							out.println("\t\t\t\t\t<is-player/>");
957 							out.println("\t\t\t\t</destination-test>");
958 							out.println("\t\t\t</assigned-damage>");
959 						} else if (line.indexOf("becomes untapped") != -1) {
960 							out.println("\t\t<triggered-ability zone='play'>");
961 							out.println("\t\t\t<become-untapped>");
962 							out.println("\t\t\t\t<test>");
963 							out
964 									.println("\t\t\t\t\t<!-- COMPLETE THE TEST APPLIED ON UNTAPPING CARD -->");
965 							out.println("\t\t\t\t\t<is-this card='tested'/>");
966 							out.println("\t\t\t\t</test>");
967 							out.println("\t\t\t</become-untapped>");
968 						} else if (line.indexOf("becomes tapped") != -1) {
969 							out.println("\t\t<triggered-ability zone='play'>");
970 							out.println("\t\t\t<become-tapped>");
971 							out.println("\t\t\t\t<test>");
972 							out
973 									.println("\t\t\t\t\t<!-- COMPLETE THE TEST APPLIED ON TAPPING CARD -->");
974 							out.println("\t\t\t\t\t<is-this card='tested'/>");
975 							out.println("\t\t\t\t</test>");
976 							out.println("\t\t\t</become-tapped>");
977 						} else if (line.indexOf("attacks") != -1) {
978 							out.println("\t\t<triggered-ability zone='play'>");
979 							out.println("\t\t\t<declared-blocking>");
980 							out.println("\t\t\t\t<blocking-test>");
981 							out.println("\t\t\t\t\t<is-this/>");
982 							out
983 									.println("\t\t\t\t\t<!-- COMPLETE THE TEST APPLIED ON BLOCKING CREATURE -->");
984 							out.println("\t\t\t\t</blocking-test>");
985 							out.println("\t\t\t\t<attacking-test>");
986 							out
987 									.println("\t\t\t\t\t<!-- COMPLETE THE TEST APPLIED ON ATTACKING CREATURE -->");
988 							out.println("\t\t\t\t</attacking-test>");
989 							out.println("\t\t\t</declared-blocking>");
990 						} else if (line.indexOf("is turned face up") != -1) {
991 							out.println("\t\t<triggered-ability zone='play'>");
992 							out.println("\t\t\t<faced-up>");
993 							out.println("\t\t\t\t<test>");
994 							out.println("\t\t\t\t<!-- UPDATE TEST ON FACED UP CARD -->");
995 							out.println("\t\t\t\t\t<is-this />");
996 							out.println("\t\t\t\t</test>");
997 							out.println("\t\t\t</faced-up>");
998 						} else {
999 							out.println("\t\t<triggered-ability zone='play'>");
1000 							out
1001 									.println("\t\t\t\t\t<!-- UPDATE THE EVENT OF THIS TRIGGERED ABILITY -->");
1002 							out.println("\t\t\t<become-tapped>");
1003 							out.println("\t\t\t\t<test>");
1004 							out
1005 									.println("\t\t\t\t\t<!-- COMPLETE THE TEST APPLIED ON TAPPING CARD -->");
1006 							out.println("\t\t\t\t\t<is-this card='tested'/>");
1007 							out.println("\t\t\t\t</test>");
1008 							out.println("\t\t\t</become-tapped>");
1009 						}
1010 						if (line.contains("target")) {
1011 							out.println("\t\t\t<cost>");
1012 							writeTarget(out, line, true);
1013 							out.println("\t\t\t</cost>");
1014 						}
1015 						out.println("\t\t\t<effects>");
1016 						writeActions(out, line, false, false);
1017 						out
1018 								.println("\t\t\t\t<!-- PUT HERE EFFECTS OF THIS TRIGGERED ABILITY -->");
1019 						out.println("\t\t\t</effects>");
1020 						out.println("\t\t</triggered-ability>");
1021 					} else if (line.indexOf("cycling") != -1) {
1022 						// Cycling
1023 						out.println("\t\t<ability ref='cycling'>");
1024 						out.println("\t\t\t<actions>");
1025 						writeCost(out, line.substring(
1026 								line.indexOf("cycling") + "cycling".length()).trim(), null);
1027 						out.println("\t\t\t</actions>");
1028 						out.println("\t\t</ability>");
1029 					} else if (line.indexOf("evoke") != -1) {
1030 						// Evoke
1031 						out.println("\t\t<ability ref='evoke"
1032 								+ (properties.contains("flash") ? "-flash" : "") + "'>");
1033 						out.println("\t\t\t<actions>");
1034 						writeCost(out, line.substring(
1035 								line.indexOf("evoke") + "evoke".length()).trim(), null);
1036 						out.println("\t\t\t</actions>");
1037 						out.println("\t\t</ability>");
1038 					} else if (line.indexOf("madness") != -1) {
1039 						// Madness
1040 						out.println("\t\t<ability ref='madness'>");
1041 						out.println("\t\t\t<actions>");
1042 						writeCost(out, line.substring(
1043 								line.indexOf("madness") + "madness".length()).trim(), null);
1044 						out.println("\t\t\t</actions>");
1045 						out.println("\t\t</ability>");
1046 					} else if (line.indexOf("soulshift") != -1) {
1047 						// Soulshift
1048 						out.println("\t\t<ability ref='"
1049 								+ line.substring(line.indexOf("soulshift")).trim().replace(" ",
1050 										"") + "'/>");
1051 					} else if (line.indexOf("echo") != -1) {
1052 						// Echo
1053 						out.println("\t\t<ability ref='echo'>");
1054 						out.println("\t\t\t<actions>");
1055 						writeCost(out, line.substring(
1056 								line.indexOf("echo") + "echo".length()).trim(), null);
1057 						out.println("\t\t\t</actions>");
1058 						out.println("\t\t</ability>");
1059 					} else if (line.indexOf("at the beginning of") != -1) {
1060 						// at the beginning of
1061 						if (!isInstant && !isSorcery) {
1062 							// a simple triggered ability
1063 							out
1064 									.println("\t\t\t<!-- UPDATE PHASE NAME, TYPE and RESOLUTION -->");
1065 							out
1066 									.println("\t\t<triggered-ability resolution='normal' zone='play'>");
1067 							out.println("\t\t\t<beginning-of-phase phase='upkeep'>");
1068 							out.println("\t\t\t\t<test ref='during-your-upkeep'/>");
1069 							out.println("\t\t\t</beginning-of-phase>");
1070 							if (line.indexOf("unless") != -1) {
1071 								out.println("\t\t\t<cost>");
1072 								out.println("\t\t\t\t<choice cancel='false'>");
1073 								out.println("\t\t\t\t\t<either>");
1074 								out.println("\t\t\t\t\t\t<pay-mana colorless='1'/>");
1075 								out.println("\t\t\t\t\t</either>");
1076 								out.println("\t\t\t\t\t<either>");
1077 								out.println("\t\t\t\t\t\t<action ref='sacrifice-this'/>");
1078 								out.println("\t\t\t\t\t</either>");
1079 								out.println("\t\t\t\t</choice>");
1080 								out.println("\t\t\t</cost>");
1081 							} else {
1082 								out.println("\t\t\t<effects>");
1083 								writeActions(out, line, false, false);
1084 								out
1085 										.println("\t\t\t\t<!-- PUT HERE EFFECTS OF THIS TRIGGERED ABILITY -->");
1086 								out.println("\t\t\t</effects>");
1087 							}
1088 							out.println("\t\t</triggered-ability>");
1089 						}
1090 					} else if (line.indexOf("cumulative upkeep") != -1) {
1091 						// Cumulative upkeep
1092 						out.println("\t\t<ability ref='cumulative-upkeep'/>");
1093 						out
1094 								.println("\t\t<triggered-ability resolution='normal' zone='play' name='cumulative-upkeep'>");
1095 						out.println("\t\t\t<beginning-of-phase phase='upkeep'>");
1096 						out.println("\t\t\t\t<test ref='during-your-upkeep'/>");
1097 						out.println("\t\t\t</beginning-of-phase>");
1098 						out.println("\t\t\t<cost>");
1099 						out.println("\t\t\t\t<choice cancel='false'>");
1100 						out.println("\t\t\t\t\t<either>");
1101 						out.println("\t\t\t\t\t\t<!-- PUT HERE THE ACTION(S) TO PAY -->");
1102 						out.println("\t\t\t\t\t\t<action ref='pay-life'>");
1103 						out.println("\t\t\t\t\t\t\t<value>");
1104 						out
1105 								.println("\t\t\t\t\t\t\t\t<counter object-name='age' card='this'/>");
1106 						out.println("\t\t\t\t\t\t\t</value>");
1107 						out.println("\t\t\t\t\t\t</action>");
1108 						out.println("\t\t\t\t\t</either>");
1109 						out.println("\t\t\t\t\t<either>");
1110 						out.println("\t\t\t\t\t\t<action ref='sacrifice-this'/>");
1111 						out.println("\t\t\t\t\t</either>");
1112 						out.println("\t\t\t\t</choice>");
1113 						out.println("\t\t\t</cost>");
1114 						out.println("\t\t</triggered-ability>");
1115 					}
1116 				}
1117 				out.println("\t</abilities>");
1118 
1119 				// Fading or vanishing counter
1120 				if (hasFading || hasVanishing || hasLessToPlay || hasMoreToPlay) {
1121 					out.println("\t<modifiers>");
1122 
1123 					if (hasMoreToPlay) {
1124 						out.println("\t\t<additional-cost-modifier linked='true'>");
1125 						out.println("\t\t\t<test>");
1126 						out.println("\t\t<!-- Complete the additional cost test -->");
1127 						out.println("\t\t\t</test>");
1128 						out.println("\t\t\t<cost>");
1129 						out.println("\t\t<!-- Update the additional cost amount -->");
1130 						out.println("\t\t\t\t<pay-mana colorless='1' />");
1131 						out.println("\t\t\t</cost>");
1132 						out.println("\t\t</additional-cost-modifier>");
1133 					}
1134 
1135 					if (hasLessToPlay) {
1136 						out.println("\t\t<additional-cost-modifier linked='true'>");
1137 						out.println("\t\t\t<test>");
1138 						out.println("\t\t<!-- Complete the cost reduction test -->");
1139 						out.println("\t\t\t</test>");
1140 						out.println("\t\t\t<cost>");
1141 						out.println("\t\t<!-- Update the cost reduction amount -->");
1142 						out.println("\t\t\t\t<pay-mana colorless='-1' />");
1143 						out.println("\t\t\t</cost>");
1144 						out.println("\t\t</additional-cost-modifier>");
1145 					}
1146 
1147 					if (hasFading) {
1148 						int fadingCounter = Integer.parseInt(hasFadingLine);
1149 						if (fadingCounter == Integer.MIN_VALUE) {
1150 							fadingCounter = 1;
1151 						}
1152 						for (int i = fadingCounter; i-- > 0;) {
1153 							out.println("\t\t<object name='fade'/>");
1154 						}
1155 					}
1156 					if (hasVanishing) {
1157 						int vanishingCounter;
1158 						if (hasVanishingLine.length() != 0)
1159 							vanishingCounter = Integer.parseInt(hasVanishingLine);
1160 						else {
1161 							vanishingCounter = 1;
1162 							out.println("\t\t<!-- NEEDS CODE FOR NUMBER OF COUNTERS -->");
1163 						}
1164 						if (vanishingCounter == Integer.MIN_VALUE) {
1165 							vanishingCounter = 1;
1166 						}
1167 						for (int i = vanishingCounter; i-- > 0;) {
1168 							out.println("\t\t<object name='time'/>");
1169 						}
1170 					}
1171 					out.println("\t</modifiers>");
1172 				}
1173 
1174 				// Attachment
1175 
1176 				if (isEquipment) {
1177 					String pow = new String();
1178 					String tou = new String();
1179 					if (equipLine.length() > 0) {
1180 						pow = equipLine.substring(0, equipLine.indexOf("/"));
1181 						tou = equipLine.substring(equipLine.indexOf("/") + 2, equipLine
1182 								.indexOf("/") + 3);
1183 					} else {
1184 						out.println("\t<!-- WRITE THE EQUIPMENT MODIFIERS -->");
1185 					}
1186 
1187 					out.println("\t<attachment>");
1188 					out.println("\t\t<modifiers>");
1189 					if (!pow.contains("0"))
1190 						out
1191 								.println("\t\t\t<register-modifier index='power' operation='add' linked='true' value='"
1192 										+ pow + "' />");
1193 					if (!tou.contains("0"))
1194 						out
1195 								.println("\t\t\t<register-modifier index='toughness' operation='add' linked='true' value='"
1196 										+ tou + "' />");
1197 					out.println("\t\t</modifiers>");
1198 					out.println("\t\t<valid-target ref='valid-creature-to-equip' />");
1199 					out.println("\t\t<valid-attachment ref='valid-equip-creature' />");
1200 					out.println("\t</attachment>");
1201 				}
1202 				if (isAura) {
1203 					out.print("\t<attachment");
1204 
1205 					if (isLocalEnchantCreature) {
1206 						if (line.indexOf("you control enchanted creature") != -1) {
1207 							out.println(" ref='control'/>");
1208 							out.println("\t<!-- Add the additional modifiers here-->");
1209 						} else if (line.startsWith("enchanted creature gets")
1210 								|| line.indexOf("enchanted creature has") != -1) {
1211 							if (line.indexOf("gets") != -1) {
1212 								String temp = line.substring(line.indexOf("gets")).split(" ")[1]
1213 										.replaceFirst("[.,]", "");
1214 								out.print(" ref='" + temp);
1215 								if (temp.indexOf("x") != -1) {
1216 									out
1217 											.println("\t<!-- UPDATE X VALUE IN MODIFIERS, SEE CARD: Blanchwood Armor-->");
1218 								}
1219 							}
1220 							if (line.indexOf("has") != -1) {
1221 								String property = line.substring(line.indexOf("has"))
1222 										.split(" ")[1].replaceFirst("[.,]", "");
1223 								if (line.indexOf("gets") != -1) {
1224 									out.println("'>");
1225 									out.println("\t\t<modifiers>");
1226 									out
1227 											.println("\t\t\t<!-- UPDATE THE MODIFIER TYPE AND THE LINKED ATTRIBUTE -->");
1228 									out.println("\t\t\t<property-modifier property='" + property
1229 											+ "' linked='true'/>");
1230 									out.println("\t\t</modifiers>");
1231 									out.println("\t</attachment>");
1232 								} else {
1233 									out.println(" ref='" + property + "'/>");
1234 								}
1235 
1236 							} else
1237 								out.println("'/>");
1238 						} else {
1239 							out.println(" ref='enchant-creature'/>");
1240 						}
1241 					} else if (isLocalEnchantLand) {
1242 						out.println(" ref='enchant-land'/>");
1243 
1244 					} else if (isLocalEnchantArtifact) {
1245 						out.println(" ref='enchant-artifact'/>");
1246 
1247 					} else if (isLocalEnchantEnchantment) {
1248 						out
1249 								.println("\t\t<valid-target ref='valid-enchantment-to-enchant' />");
1250 						out
1251 								.println("\t\t<valid-attachment ref='valid-enchant-enchantment' />");
1252 
1253 					} else if (isLocalEnchantCreatureArtifact) {
1254 						out.println(" ref='enchant-artifact-creature'/>");
1255 
1256 					} else if (isLocalEnchantPermanent) {
1257 						out.println(" ref='enchant'/>");
1258 					}
1259 				}
1260 				out.println("</card>");
1261 				IOUtils.closeQuietly(out);
1262 				nbCard++;
1263 			}
1264 		} catch (FileNotFoundException e) {
1265 			System.err.println("Error openning file '" + oracleFile + "' : " + e);
1266 		} catch (IOException e) {
1267 			System.err.println("IOError reading file '" + oracleFile + "' : " + e);
1268 		}
1269 		System.out.println("Success Parsing : " + nbCard + " card(s)");
1270 	}
1271 
1272 	/***
1273 	 * <ul>
1274 	 * Argument are (in this order :
1275 	 * <li>Oracle source file
1276 	 * <li>destination directory
1277 	 * </ul>
1278 	 * 
1279 	 * @param args
1280 	 */
1281 	public static void main(String... args) {
1282 		options = new Options();
1283 		final CmdLineParser parser = new CmdLineParser(options);
1284 		try {
1285 			parser.parseArgument(args);
1286 		} catch (CmdLineException e) {
1287 			// Display help
1288 			if (!options.isHelp()) {
1289 				System.out.println("Wrong parameters : " + e.getMessage());
1290 			} else {
1291 				System.out.println("Usage");
1292 			}
1293 			parser.setUsageWidth(100);
1294 			parser.printUsage(System.out);
1295 			System.exit(-1);
1296 			return;
1297 		}
1298 
1299 		if (options.isVersion()) {
1300 			// Display version
1301 			System.out.println("Version is " + IdConst.VERSION);
1302 			System.exit(-1);
1303 			return;
1304 		}
1305 
1306 		if (options.isHelp()) {
1307 			// Display help
1308 			System.out.println("Usage");
1309 			parser.setUsageWidth(100);
1310 			parser.printUsage(System.out);
1311 			System.exit(-1);
1312 			return;
1313 		}
1314 
1315 		// The oracle source file
1316 		final String oracle = options.getOracleFile();
1317 
1318 		// the directory destination end with the file separator
1319 		String destination = FilenameUtils.separatorsToWindows(options
1320 				.getDestination());
1321 		if (!destination.endsWith("/")) {
1322 			destination += "/";
1323 		}
1324 
1325 		// Create the destination directories
1326 		try {
1327 			new File(destination).mkdirs();
1328 		} catch (Exception e) {
1329 			// Ignore this error and continue
1330 		}
1331 		new Oracle2Xml().serialize(MToolKit.getFile(oracle), MToolKit
1332 				.getFile(destination), MToolKit.getFile("tbs/" + TBS_NAME
1333 				+ "/recycled/"));
1334 	}
1335 
1336 	/***
1337 	 * Write X expression for pay-mana action
1338 	 * 
1339 	 * @param out
1340 	 *          the output were the pay-mana would be written.
1341 	 * @param manaCost
1342 	 *          the mana cost.
1343 	 * @param writeFixPart
1344 	 *          is the fixed part of mana cost is written or not.
1345 	 * @see net.sf.firemox.xml.action.PayMana
1346 	 */
1347 	private void writeXmanaCost(PrintWriter out, int[] manaCost,
1348 			boolean writeFixPart) {
1349 
1350 		// The fixed part
1351 		if (writeFixPart) {
1352 			out.print("\t\t\t\t<pay-mana ");
1353 			for (int i = 6; i-- > 0;) {
1354 				if (manaCost[i] > 0) {
1355 					out.print(extractColor(i) + "='" + manaCost[i] + "' ");
1356 				}
1357 			}
1358 			out.println("/>");
1359 		}
1360 
1361 		// The X part
1362 		if (manaCost[6] > 0) {
1363 			out
1364 					.println("\t\t\t\t<!-- UPDATE THE TEXT AND AMOUNT OF MIN/MAXI COLORLESS MANA TO PAY -->");
1365 			out
1366 					.println("\t\t\t\t<input-number min='0' controller='you' operation='set' register='stack' index='0' name='%'>");
1367 			out.println("\t\t\t\t\t<text>%x-value</text>");
1368 			if (manaCost[6] > 1) {
1369 				out.println("\t\t\t\t\t<max register='you' index='manapool'/>");
1370 			} else {
1371 				// XX.. like
1372 				out.println("\t\t\t\t\t<max>");
1373 				out.println("\t\t\t\t\t\t<div right='" + manaCost[6] + "'>");
1374 				out.println("\t\t\t\t\t\t\t<left register='you' index='manapool'>");
1375 				out.println("\t\t\t\t\t\t</div>");
1376 				out.println("\t\t\t\t\t</max>");
1377 			}
1378 			out.println("\t\t\t\t</input-number>");
1379 			out.println("\t\t\t\t<pay-mana>");
1380 			out.println("\t\t\t\t\t<colorless register='stack' index='0'/>");
1381 			out.println("\t\t\t\t</pay-mana>");
1382 		}
1383 	}
1384 
1385 	/***
1386 	 * Write X expression for give-mana action
1387 	 * 
1388 	 * @param out
1389 	 *          the output were the pay-mana would be written.