Camtech075

Untitled

Oct 17th, 2011
219
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.57 KB | None | 0 0
  1. /*
  2. * FE Editor - GBA Fire Emblem (U) ROM editor
  3. *
  4. * Copyright (C) 2008-2009 Hextator,
  5. * hectorofchad (AIM) [email protected] (MSN)
  6. *
  7. * Major thanks to Zahlman (AIM/MSN: [email protected]) for optimization,
  8. * organization and modularity improvements.
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License version 3
  12. * as published by the Free Software Foundation
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, write to the Free Software
  21. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  22. *
  23. * <Description> This class provides a dialog for inserting custom battle
  24. * animations for classes
  25. */
  26.  
  27. package fe_editor;
  28.  
  29. import java.awt.event.ActionListener;
  30. import java.awt.event.ActionEvent;
  31. import java.io.File;
  32. import java.io.IOException;
  33. import java.util.Scanner;
  34. import javax.swing.JPanel;
  35. import javax.swing.JScrollPane;
  36. import javax.swing.JTextArea;
  37. import javax.swing.JButton;
  38. //import javax.swing.JLabel;
  39. import Controls.LabelledHexSpinner;
  40. import Graphics.GBA_Image;
  41. import Model.Game;
  42. import Model.Animation_Builder;
  43. import Model.Pointer_Table;
  44.  
  45. // FIXME: Extract common code between weapon and spell animation inserters.
  46.  
  47. // XXX Doesn't actually use a pointer table. Instead, it works with an
  48. // AnimationBuilder to create an animation.
  49. public class Class_Animation_Creator
  50. extends Editor<Pointer_Table>
  51. implements ActionListener
  52. {
  53. private JPanel buttonPanel = new JPanel();
  54. //private JPanel soundSpinnerPanel = new JPanel();
  55. //private JPanel durationSpinnerPanel = new JPanel();
  56.  
  57. private LabelledHexSpinner commandValue = new LabelledHexSpinner(
  58. null, "Input command:", 2
  59. );
  60.  
  61. private LabelledHexSpinner durationValue = new LabelledHexSpinner(
  62. null, "Input frame duration:", 2 // based on Animation_Builder.MAX_DURATION_ALLOWED
  63. );
  64.  
  65. private LabelledHexSpinner soundValue = new LabelledHexSpinner(
  66. null, "Input music ID:", 4
  67. );
  68.  
  69. private JTextArea diagnosticLabel = new JTextArea();
  70. private JScrollPane diagnosticPane;
  71. private JPanel diagnosticPanel = new JPanel();
  72. private JPanel scriptPanel = new JPanel();
  73. private JButton insertButton = new JButton("Insert Frame");
  74. private JButton insertThrowableButton = new JButton("Insert Throwable Sprite");
  75. private JPanel insertThrowablePanel = new JPanel();
  76. private JButton commandButton = new JButton("Add Command");
  77. private JButton soundButton = new JButton("Add Sound");
  78. private JButton modeTerminatorButton = new JButton("Add Mode Terminator");
  79. private JButton loopButton = new JButton("Add Loop Marker");
  80. private JButton applyButton = new JButton("Apply Animation");
  81. private JButton scriptButton = new JButton("Load From Script");
  82. private JButton resetButton = new JButton("Reset Animation");
  83. private JButton quitButton = new JButton("Quit");
  84. private JButton saveButton = new JButton("Save To File...");
  85.  
  86. private static boolean busy = false;
  87.  
  88. private Animation_Builder builder;
  89.  
  90. // FIXME Make script reading a process. Make processes interruptible?
  91. private String lastPath = "N/A";
  92.  
  93. public Class_Animation_Creator(View view)
  94. {
  95. super(view);
  96.  
  97. this.view = view;
  98.  
  99. insertThrowableButton.addActionListener(this);
  100. insertThrowablePanel.add(insertThrowableButton);
  101. insertThrowablePanel.setMaximumSize(insertThrowablePanel.getPreferredSize());
  102. add(insertThrowablePanel);
  103.  
  104. JPanel commandSpinnerPanel = new JPanel();
  105. commandSpinnerPanel.add(commandValue);
  106. commandButton.addActionListener(this);
  107. commandSpinnerPanel.add(commandButton);
  108. commandSpinnerPanel.setMaximumSize(commandSpinnerPanel.getPreferredSize());
  109. add(commandSpinnerPanel);
  110.  
  111. JPanel soundSpinnerPanel = new JPanel();
  112. soundSpinnerPanel.add(soundValue);
  113. soundButton.addActionListener(this);
  114. soundSpinnerPanel.add(soundButton);
  115. soundSpinnerPanel.setMaximumSize(soundSpinnerPanel.getPreferredSize());
  116. add(soundSpinnerPanel);
  117.  
  118. JPanel durationSpinnerPanel = new JPanel();
  119. durationSpinnerPanel.add(durationValue);
  120. insertButton.addActionListener(this);
  121. durationSpinnerPanel.add(insertButton);
  122. durationSpinnerPanel.setMaximumSize(durationSpinnerPanel.getPreferredSize());
  123. add(durationSpinnerPanel);
  124.  
  125. modeTerminatorButton.addActionListener(this);
  126. modeTerminatorButton.setEnabled(false);
  127. buttonPanel.add(modeTerminatorButton);
  128. loopButton.addActionListener(this);
  129. loopButton.setEnabled(false);
  130. buttonPanel.add(loopButton);
  131. buttonPanel.setMaximumSize(buttonPanel.getPreferredSize());
  132. add(buttonPanel);
  133.  
  134. scriptButton.addActionListener(this);
  135. scriptPanel.add(scriptButton);
  136. resetButton.addActionListener(this);
  137. scriptPanel.add(resetButton);
  138. saveButton.addActionListener(this);
  139. scriptPanel.add(saveButton);
  140. quitButton.addActionListener(this);
  141. scriptPanel.add(quitButton);
  142. scriptPanel.setMaximumSize(scriptPanel.getPreferredSize());
  143. add(scriptPanel);
  144.  
  145. diagnosticLabel.setEditable(false);
  146. diagnosticLabel.setColumns(48);
  147. diagnosticLabel.setRows(5);
  148. diagnosticPane = new JScrollPane(diagnosticLabel);
  149. diagnosticPanel.add(diagnosticPane);
  150. diagnosticPanel.setMaximumSize(diagnosticPanel.getPreferredSize());
  151. add(diagnosticPanel);
  152. }
  153.  
  154. @Override
  155. public void setup(Game game)
  156. {
  157. // table is left as null
  158. builder = new Animation_Builder();
  159.  
  160. update();
  161. }
  162.  
  163. private void update() {
  164. String diagnosticString = "";
  165. if (builder.getMode() == Animation_Builder.MAX_MODE_COUNT)
  166. diagnosticString += "Mode: Complete\n";
  167. else
  168. diagnosticString += String.format
  169. (
  170. "Mode: %d\n",
  171. builder.getMode() + 1
  172. );
  173. //diagnosticString += String.format
  174. //(
  175. // "0x85 command count for this mode: %d\n",
  176. // builder.getCommandCount()
  177. //);
  178. diagnosticString += String.format
  179. (
  180. "Animation frame count for this mode: %d\n",
  181. builder.getFrameCount()
  182. );
  183. diagnosticString += "Last path: " + lastPath;
  184. diagnosticLabel.setText(diagnosticString);
  185. if
  186. (
  187. builder.getMode() > 0
  188. || builder.getFrameCount() > 0
  189. //|| builder.getCommandCount() > 0
  190. )
  191. insertThrowableButton.setEnabled(false);
  192. if
  193. (
  194. builder.getFrameCount() == 0
  195. //|| builder.getCommandCount() == 0
  196. )
  197. modeTerminatorButton.setEnabled(false);
  198. else
  199. modeTerminatorButton.setEnabled(true);
  200. if (builder.getMode() < Animation_Builder.MAX_MODE_COUNT)
  201. applyButton.setEnabled(false);
  202. else
  203. applyButton.setEnabled(true);
  204. if (!builder.canLoop() || builder.hasLoop())
  205. loopButton.setEnabled(false);
  206. else
  207. loopButton.setEnabled(true);
  208. }
  209.  
  210. // Convenience method
  211. private GBA_Image processImage(File loadedFile) {
  212. if (loadedFile != null) {
  213. lastPath = loadedFile.getPath();
  214. }
  215. return new GBA_Image(loadedFile, builder.sharedPalette());
  216. }
  217. // processImage method; tested and working!
  218.  
  219. class SyntaxException extends Exception
  220. {
  221. int line;
  222. String info;
  223.  
  224. public SyntaxException(int line)
  225. {
  226. this.line = line;
  227. info = "!";
  228. }
  229.  
  230. public SyntaxException(int line, String info)
  231. {
  232. this.line = line;
  233. this.info = ":\n" + info;
  234. }
  235.  
  236. @Override
  237. public String getMessage()
  238. {
  239. return String.format("Error parsing line %d%s", line, info);
  240. }
  241. }
  242.  
  243. private void loadFromScript()
  244. {
  245. Scanner scriptFileReader = null;
  246.  
  247. try
  248. {
  249. File scriptFile = Common_Dialogs.showOpenFileDialog("animation script");
  250. scriptFileReader = new Scanner(scriptFile);
  251. loadFromScript_helper(scriptFile, scriptFileReader);
  252. }
  253. catch (SyntaxException se)
  254. {
  255. Common_Dialogs.showGenericErrorDialog(se.getMessage());
  256. }
  257. catch (IOException ioe)
  258. {
  259. Common_Dialogs.showStreamErrorDialog();
  260. }
  261. catch (Exception e)
  262. {
  263. Common_Dialogs.showGenericErrorDialog("Unexpected error loading or reading the script");
  264. }
  265. finally
  266. {
  267. try { scriptFileReader.close(); }
  268. catch (Exception e) {}
  269. }
  270. }
  271.  
  272. // Convenience method
  273. private void loadFromScript_helper(File scriptFile, Scanner scriptFileReader)
  274. throws Exception
  275. {
  276. int line = 0;
  277. int tempInt = 0;
  278. boolean blockComment = false;
  279.  
  280. while (scriptFileReader.hasNextLine())
  281. {
  282. String loadedScriptLine = scriptFileReader.nextLine();
  283. line++;
  284.  
  285. if (loadedScriptLine.length() == 0) { continue; }
  286.  
  287. if (blockComment)
  288. {
  289. if (loadedScriptLine.charAt(0) == '*') { blockComment = false; }
  290. continue;
  291. }
  292.  
  293. update();
  294.  
  295. switch (loadedScriptLine.charAt(0))
  296. {
  297. case '/':
  298. if (loadedScriptLine.length() >= 2 && loadedScriptLine.charAt(1) == '*')
  299. {
  300. blockComment = true;
  301. }
  302. break;
  303.  
  304. case 'C':
  305. try { tempInt = Integer.parseInt(loadedScriptLine.substring(1, 3), 16); }
  306. catch (Exception e) { throw new SyntaxException(line); }
  307. builder.addCommand((byte) tempInt);
  308. break;
  309.  
  310. case 'S':
  311. try { tempInt = Integer.parseInt(loadedScriptLine.substring(1, 5), 16); }
  312. catch (Exception e) { throw new SyntaxException(line); }
  313. builder.addSoundCommand((short) tempInt);
  314. break;
  315.  
  316. case 'L':
  317. if (!builder.canLoop()) {
  318. throw new SyntaxException(line, "There is nowhere to loop to.");
  319. } else if (builder.hasLoop()) {
  320. throw new SyntaxException(line, "Can't specify more than one loop.");
  321. }
  322. builder.addLoopMarker();
  323. break;
  324.  
  325. case '~':
  326. if (builder.getFrameCount() == 0)
  327. {
  328. throw new SyntaxException
  329. (
  330. line,
  331. "Can't add a terminator to an empty mode."
  332. );
  333. }
  334. builder.addModeTerminator();
  335. break;
  336.  
  337. default:
  338. if (loadedScriptLine.indexOf("-") == -1)
  339. {
  340. throw new SyntaxException(line);
  341. }
  342.  
  343. boolean usePath = loadedScriptLine.indexOf("p-") != -1;
  344.  
  345. final int addFrame = 0;
  346. final int addThrowable = 1;
  347. int type = addFrame;
  348. if (loadedScriptLine.charAt(0) == 'T')
  349. {
  350. type = addThrowable;
  351. if (builder.getMode() > 0 || builder.getFrameCount() > 0)
  352. {
  353. throw new SyntaxException
  354. (
  355. line,
  356. "Throwable sprites can only be specified at the beginning"
  357. );
  358. }
  359. }
  360. int i = 0;
  361. if (type == addFrame)
  362. {
  363. // FIXME: use a Scanner or something
  364. // Jeez, even C++ makes parsing easier than this
  365. for (; i < loadedScriptLine.length(); i++)
  366. {
  367. try { tempInt = Integer.parseInt(loadedScriptLine.substring(i, i + 1)); }
  368. catch (Exception e) { break; }
  369. }
  370. try { tempInt = Integer.parseInt(loadedScriptLine.substring(0, i)); }
  371. catch (Exception e) { throw new SyntaxException(line); }
  372. }
  373. int duration = tempInt;
  374. i = loadedScriptLine.indexOf("-");
  375. if (++i >= loadedScriptLine.length())
  376. {
  377. loadedScriptLine = "a frame";
  378. }
  379. else
  380. {
  381. for (; i < loadedScriptLine.length(); i++)
  382. {
  383. if (loadedScriptLine.charAt(i) != ' ') { break; }
  384. }
  385. loadedScriptLine = loadedScriptLine.substring(i);
  386. }
  387. File loadedFile;
  388. if (!usePath)
  389. {
  390. //Prompt user for a bitmap
  391. loadedFile = Common_Dialogs.showOpenFileDialog(loadedScriptLine);
  392. }
  393. else
  394. {
  395. loadedFile = new File
  396. (
  397. scriptFile.getPath().substring
  398. (
  399. 0,
  400. scriptFile.getParent().length() + 1
  401. )
  402. + loadedScriptLine
  403. );
  404. }
  405. if (loadedFile == null)
  406. {
  407. throw new IOException();
  408. }
  409. lastPath = loadedFile.getPath();
  410. GBA_Image testConverter = processImage(loadedFile);
  411. switch (type)
  412. {
  413. case addFrame:
  414. // Hextator: Made this a do while to force
  415. // additions of frames with a duration of 0
  416. // (which is valid) without causing an infinite loop
  417. // (which was a result of using <= instead of a concrete
  418. // inequality)
  419. do
  420. {
  421. int tempDuration = Math.min(
  422. duration, Animation_Builder.MAX_DURATION_ALLOWED
  423. );
  424. duration -= tempDuration;
  425. // Hextator: Should be allowed to use shorts
  426. // (Invalid durations are caught by the model; the duration
  427. // actually does span 2 bytes in the data, it's just that
  428. // the maximum SAFE value only needs a byte)
  429. if (!builder.addFrame(testConverter, (short)tempDuration))
  430. {
  431. Common_Dialogs.showGenericErrorDialog("Invalid frame!");
  432. return;
  433. }
  434. } while (duration > 0);
  435. break;
  436.  
  437. case addThrowable:
  438. if (!builder.setThrowableSprite(testConverter))
  439. {
  440. // Show an error maybe?
  441. return;
  442. }
  443. }
  444. break;
  445. }
  446. }
  447. }
  448. // loadFromScript method; needs testing
  449.  
  450. // ActionListening code
  451.  
  452. public void actionPerformed(ActionEvent e)
  453. {
  454. if (busy)
  455. {
  456. Common_Dialogs.showBusyDialog(this);
  457. return;
  458. }
  459.  
  460. String command = e.getActionCommand();
  461.  
  462. if (command.equals("Quit"))
  463. // FIXME: Make script reading interruptible by quit command.
  464. // Actually, make everything cancel-able in a nice way.
  465. {
  466. quit();
  467. return;
  468. }
  469.  
  470. busy = true;
  471.  
  472. if (command.equals("Save To File...")) {
  473. try {
  474. builder.create().writeToFile(
  475. Common_Dialogs.showSaveFileDialog("new animation")
  476. );
  477. javax.swing.JOptionPane.showMessageDialog(
  478. null,
  479. "Animation saved!",
  480. "Operation complete",
  481. javax.swing.JOptionPane.INFORMATION_MESSAGE
  482. );
  483. } catch (IOException ioe) {
  484. Common_Dialogs.showStreamErrorDialog();
  485. } catch (Exception e2) {
  486. Common_Dialogs.showGenericErrorDialog(e2.getMessage());
  487. }
  488. } else if (command.equals("Insert Frame"))
  489. {
  490. // Prompt user for a bitmap
  491. File loadedFile = Common_Dialogs.showOpenFileDialog("image of animation frame");
  492. try {
  493. GBA_Image testConverter = processImage(loadedFile);
  494. // Hextator: See note in the script processor about why
  495. // the duration is expected to be a short now
  496. builder.addFrame(
  497. testConverter, (short)(durationValue.getValue())
  498. );
  499. } catch (Exception e2) {
  500. Common_Dialogs.showGenericErrorDialog(e2.getMessage());
  501. }
  502. }
  503. else if (command.equals("Add Command"))
  504. {
  505. builder.addCommand((byte)(commandValue.getValue()));
  506. }
  507. else if (command.equals("Add Sound"))
  508. {
  509. builder.addSoundCommand((short)(soundValue.getValue()));
  510. }
  511. else if (command.equals("Add Mode Terminator"))
  512. {
  513. builder.addModeTerminator();
  514. }
  515. else if (command.equals("Save Animation..."))
  516. {
  517. File tempFile = Common_Dialogs.showSaveFileDialog("animation");
  518. try {
  519. if (tempFile != null) {
  520. builder.create().writeToFile(tempFile);
  521. }
  522. }
  523. catch (Exception e2)
  524. {
  525. Common_Dialogs.showStreamErrorDialog();
  526. }
  527. }
  528. else if (command.equals("Load From Script"))
  529. {
  530. loadFromScript();
  531. }
  532. else if (command.equals("Reset Animation"))
  533. {
  534. builder = new Animation_Builder();
  535. lastPath = "N/A";
  536. insertThrowableButton.setEnabled(true);
  537. loopButton.setEnabled(true);
  538. modeTerminatorButton.setEnabled(false);
  539. applyButton.setEnabled(false);
  540. }
  541. else if (command.equals("Insert Throwable Sprite"))
  542. {
  543. // Prompt user for a bitmap
  544. File loadedFile = Common_Dialogs.showOpenFileDialog("image of throwable sprite");
  545. try {
  546. builder.setThrowableSprite(processImage(loadedFile));
  547. } catch (Exception e3) {
  548. Common_Dialogs.showGenericErrorDialog(e3.getMessage());
  549. }
  550. }
  551. else if (command.equals("Add Loop Marker"))
  552. {
  553. builder.addLoopMarker();
  554. }
  555.  
  556. busy = false;
  557. update();
  558. }
  559. }
  560.  
  561.  
Advertisement
Add Comment
Please, Sign In to add comment