Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * FE Editor - GBA Fire Emblem (U) ROM editor
- *
- * Copyright (C) 2008-2009 Hextator,
- * hectorofchad (AIM) [email protected] (MSN)
- *
- * Major thanks to Zahlman (AIM/MSN: [email protected]) for optimization,
- * organization and modularity improvements.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3
- * as published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * <Description> This class provides a dialog for inserting custom battle
- * animations for classes
- */
- package fe_editor;
- import java.awt.event.ActionListener;
- import java.awt.event.ActionEvent;
- import java.io.File;
- import java.io.IOException;
- import java.util.Scanner;
- import javax.swing.JPanel;
- import javax.swing.JScrollPane;
- import javax.swing.JTextArea;
- import javax.swing.JButton;
- //import javax.swing.JLabel;
- import Controls.LabelledHexSpinner;
- import Graphics.GBA_Image;
- import Model.Game;
- import Model.Animation_Builder;
- import Model.Pointer_Table;
- // FIXME: Extract common code between weapon and spell animation inserters.
- // XXX Doesn't actually use a pointer table. Instead, it works with an
- // AnimationBuilder to create an animation.
- public class Class_Animation_Creator
- extends Editor<Pointer_Table>
- implements ActionListener
- {
- private JPanel buttonPanel = new JPanel();
- //private JPanel soundSpinnerPanel = new JPanel();
- //private JPanel durationSpinnerPanel = new JPanel();
- private LabelledHexSpinner commandValue = new LabelledHexSpinner(
- null, "Input command:", 2
- );
- private LabelledHexSpinner durationValue = new LabelledHexSpinner(
- null, "Input frame duration:", 2 // based on Animation_Builder.MAX_DURATION_ALLOWED
- );
- private LabelledHexSpinner soundValue = new LabelledHexSpinner(
- null, "Input music ID:", 4
- );
- private JTextArea diagnosticLabel = new JTextArea();
- private JScrollPane diagnosticPane;
- private JPanel diagnosticPanel = new JPanel();
- private JPanel scriptPanel = new JPanel();
- private JButton insertButton = new JButton("Insert Frame");
- private JButton insertThrowableButton = new JButton("Insert Throwable Sprite");
- private JPanel insertThrowablePanel = new JPanel();
- private JButton commandButton = new JButton("Add Command");
- private JButton soundButton = new JButton("Add Sound");
- private JButton modeTerminatorButton = new JButton("Add Mode Terminator");
- private JButton loopButton = new JButton("Add Loop Marker");
- private JButton applyButton = new JButton("Apply Animation");
- private JButton scriptButton = new JButton("Load From Script");
- private JButton resetButton = new JButton("Reset Animation");
- private JButton quitButton = new JButton("Quit");
- private JButton saveButton = new JButton("Save To File...");
- private static boolean busy = false;
- private Animation_Builder builder;
- // FIXME Make script reading a process. Make processes interruptible?
- private String lastPath = "N/A";
- public Class_Animation_Creator(View view)
- {
- super(view);
- this.view = view;
- insertThrowableButton.addActionListener(this);
- insertThrowablePanel.add(insertThrowableButton);
- insertThrowablePanel.setMaximumSize(insertThrowablePanel.getPreferredSize());
- add(insertThrowablePanel);
- JPanel commandSpinnerPanel = new JPanel();
- commandSpinnerPanel.add(commandValue);
- commandButton.addActionListener(this);
- commandSpinnerPanel.add(commandButton);
- commandSpinnerPanel.setMaximumSize(commandSpinnerPanel.getPreferredSize());
- add(commandSpinnerPanel);
- JPanel soundSpinnerPanel = new JPanel();
- soundSpinnerPanel.add(soundValue);
- soundButton.addActionListener(this);
- soundSpinnerPanel.add(soundButton);
- soundSpinnerPanel.setMaximumSize(soundSpinnerPanel.getPreferredSize());
- add(soundSpinnerPanel);
- JPanel durationSpinnerPanel = new JPanel();
- durationSpinnerPanel.add(durationValue);
- insertButton.addActionListener(this);
- durationSpinnerPanel.add(insertButton);
- durationSpinnerPanel.setMaximumSize(durationSpinnerPanel.getPreferredSize());
- add(durationSpinnerPanel);
- modeTerminatorButton.addActionListener(this);
- modeTerminatorButton.setEnabled(false);
- buttonPanel.add(modeTerminatorButton);
- loopButton.addActionListener(this);
- loopButton.setEnabled(false);
- buttonPanel.add(loopButton);
- buttonPanel.setMaximumSize(buttonPanel.getPreferredSize());
- add(buttonPanel);
- scriptButton.addActionListener(this);
- scriptPanel.add(scriptButton);
- resetButton.addActionListener(this);
- scriptPanel.add(resetButton);
- saveButton.addActionListener(this);
- scriptPanel.add(saveButton);
- quitButton.addActionListener(this);
- scriptPanel.add(quitButton);
- scriptPanel.setMaximumSize(scriptPanel.getPreferredSize());
- add(scriptPanel);
- diagnosticLabel.setEditable(false);
- diagnosticLabel.setColumns(48);
- diagnosticLabel.setRows(5);
- diagnosticPane = new JScrollPane(diagnosticLabel);
- diagnosticPanel.add(diagnosticPane);
- diagnosticPanel.setMaximumSize(diagnosticPanel.getPreferredSize());
- add(diagnosticPanel);
- }
- @Override
- public void setup(Game game)
- {
- // table is left as null
- builder = new Animation_Builder();
- update();
- }
- private void update() {
- String diagnosticString = "";
- if (builder.getMode() == Animation_Builder.MAX_MODE_COUNT)
- diagnosticString += "Mode: Complete\n";
- else
- diagnosticString += String.format
- (
- "Mode: %d\n",
- builder.getMode() + 1
- );
- //diagnosticString += String.format
- //(
- // "0x85 command count for this mode: %d\n",
- // builder.getCommandCount()
- //);
- diagnosticString += String.format
- (
- "Animation frame count for this mode: %d\n",
- builder.getFrameCount()
- );
- diagnosticString += "Last path: " + lastPath;
- diagnosticLabel.setText(diagnosticString);
- if
- (
- builder.getMode() > 0
- || builder.getFrameCount() > 0
- //|| builder.getCommandCount() > 0
- )
- insertThrowableButton.setEnabled(false);
- if
- (
- builder.getFrameCount() == 0
- //|| builder.getCommandCount() == 0
- )
- modeTerminatorButton.setEnabled(false);
- else
- modeTerminatorButton.setEnabled(true);
- if (builder.getMode() < Animation_Builder.MAX_MODE_COUNT)
- applyButton.setEnabled(false);
- else
- applyButton.setEnabled(true);
- if (!builder.canLoop() || builder.hasLoop())
- loopButton.setEnabled(false);
- else
- loopButton.setEnabled(true);
- }
- // Convenience method
- private GBA_Image processImage(File loadedFile) {
- if (loadedFile != null) {
- lastPath = loadedFile.getPath();
- }
- return new GBA_Image(loadedFile, builder.sharedPalette());
- }
- // processImage method; tested and working!
- class SyntaxException extends Exception
- {
- int line;
- String info;
- public SyntaxException(int line)
- {
- this.line = line;
- info = "!";
- }
- public SyntaxException(int line, String info)
- {
- this.line = line;
- this.info = ":\n" + info;
- }
- @Override
- public String getMessage()
- {
- return String.format("Error parsing line %d%s", line, info);
- }
- }
- private void loadFromScript()
- {
- Scanner scriptFileReader = null;
- try
- {
- File scriptFile = Common_Dialogs.showOpenFileDialog("animation script");
- scriptFileReader = new Scanner(scriptFile);
- loadFromScript_helper(scriptFile, scriptFileReader);
- }
- catch (SyntaxException se)
- {
- Common_Dialogs.showGenericErrorDialog(se.getMessage());
- }
- catch (IOException ioe)
- {
- Common_Dialogs.showStreamErrorDialog();
- }
- catch (Exception e)
- {
- Common_Dialogs.showGenericErrorDialog("Unexpected error loading or reading the script");
- }
- finally
- {
- try { scriptFileReader.close(); }
- catch (Exception e) {}
- }
- }
- // Convenience method
- private void loadFromScript_helper(File scriptFile, Scanner scriptFileReader)
- throws Exception
- {
- int line = 0;
- int tempInt = 0;
- boolean blockComment = false;
- while (scriptFileReader.hasNextLine())
- {
- String loadedScriptLine = scriptFileReader.nextLine();
- line++;
- if (loadedScriptLine.length() == 0) { continue; }
- if (blockComment)
- {
- if (loadedScriptLine.charAt(0) == '*') { blockComment = false; }
- continue;
- }
- update();
- switch (loadedScriptLine.charAt(0))
- {
- case '/':
- if (loadedScriptLine.length() >= 2 && loadedScriptLine.charAt(1) == '*')
- {
- blockComment = true;
- }
- break;
- case 'C':
- try { tempInt = Integer.parseInt(loadedScriptLine.substring(1, 3), 16); }
- catch (Exception e) { throw new SyntaxException(line); }
- builder.addCommand((byte) tempInt);
- break;
- case 'S':
- try { tempInt = Integer.parseInt(loadedScriptLine.substring(1, 5), 16); }
- catch (Exception e) { throw new SyntaxException(line); }
- builder.addSoundCommand((short) tempInt);
- break;
- case 'L':
- if (!builder.canLoop()) {
- throw new SyntaxException(line, "There is nowhere to loop to.");
- } else if (builder.hasLoop()) {
- throw new SyntaxException(line, "Can't specify more than one loop.");
- }
- builder.addLoopMarker();
- break;
- case '~':
- if (builder.getFrameCount() == 0)
- {
- throw new SyntaxException
- (
- line,
- "Can't add a terminator to an empty mode."
- );
- }
- builder.addModeTerminator();
- break;
- default:
- if (loadedScriptLine.indexOf("-") == -1)
- {
- throw new SyntaxException(line);
- }
- boolean usePath = loadedScriptLine.indexOf("p-") != -1;
- final int addFrame = 0;
- final int addThrowable = 1;
- int type = addFrame;
- if (loadedScriptLine.charAt(0) == 'T')
- {
- type = addThrowable;
- if (builder.getMode() > 0 || builder.getFrameCount() > 0)
- {
- throw new SyntaxException
- (
- line,
- "Throwable sprites can only be specified at the beginning"
- );
- }
- }
- int i = 0;
- if (type == addFrame)
- {
- // FIXME: use a Scanner or something
- // Jeez, even C++ makes parsing easier than this
- for (; i < loadedScriptLine.length(); i++)
- {
- try { tempInt = Integer.parseInt(loadedScriptLine.substring(i, i + 1)); }
- catch (Exception e) { break; }
- }
- try { tempInt = Integer.parseInt(loadedScriptLine.substring(0, i)); }
- catch (Exception e) { throw new SyntaxException(line); }
- }
- int duration = tempInt;
- i = loadedScriptLine.indexOf("-");
- if (++i >= loadedScriptLine.length())
- {
- loadedScriptLine = "a frame";
- }
- else
- {
- for (; i < loadedScriptLine.length(); i++)
- {
- if (loadedScriptLine.charAt(i) != ' ') { break; }
- }
- loadedScriptLine = loadedScriptLine.substring(i);
- }
- File loadedFile;
- if (!usePath)
- {
- //Prompt user for a bitmap
- loadedFile = Common_Dialogs.showOpenFileDialog(loadedScriptLine);
- }
- else
- {
- loadedFile = new File
- (
- scriptFile.getPath().substring
- (
- 0,
- scriptFile.getParent().length() + 1
- )
- + loadedScriptLine
- );
- }
- if (loadedFile == null)
- {
- throw new IOException();
- }
- lastPath = loadedFile.getPath();
- GBA_Image testConverter = processImage(loadedFile);
- switch (type)
- {
- case addFrame:
- // Hextator: Made this a do while to force
- // additions of frames with a duration of 0
- // (which is valid) without causing an infinite loop
- // (which was a result of using <= instead of a concrete
- // inequality)
- do
- {
- int tempDuration = Math.min(
- duration, Animation_Builder.MAX_DURATION_ALLOWED
- );
- duration -= tempDuration;
- // Hextator: Should be allowed to use shorts
- // (Invalid durations are caught by the model; the duration
- // actually does span 2 bytes in the data, it's just that
- // the maximum SAFE value only needs a byte)
- if (!builder.addFrame(testConverter, (short)tempDuration))
- {
- Common_Dialogs.showGenericErrorDialog("Invalid frame!");
- return;
- }
- } while (duration > 0);
- break;
- case addThrowable:
- if (!builder.setThrowableSprite(testConverter))
- {
- // Show an error maybe?
- return;
- }
- }
- break;
- }
- }
- }
- // loadFromScript method; needs testing
- // ActionListening code
- public void actionPerformed(ActionEvent e)
- {
- if (busy)
- {
- Common_Dialogs.showBusyDialog(this);
- return;
- }
- String command = e.getActionCommand();
- if (command.equals("Quit"))
- // FIXME: Make script reading interruptible by quit command.
- // Actually, make everything cancel-able in a nice way.
- {
- quit();
- return;
- }
- busy = true;
- if (command.equals("Save To File...")) {
- try {
- builder.create().writeToFile(
- Common_Dialogs.showSaveFileDialog("new animation")
- );
- javax.swing.JOptionPane.showMessageDialog(
- null,
- "Animation saved!",
- "Operation complete",
- javax.swing.JOptionPane.INFORMATION_MESSAGE
- );
- } catch (IOException ioe) {
- Common_Dialogs.showStreamErrorDialog();
- } catch (Exception e2) {
- Common_Dialogs.showGenericErrorDialog(e2.getMessage());
- }
- } else if (command.equals("Insert Frame"))
- {
- // Prompt user for a bitmap
- File loadedFile = Common_Dialogs.showOpenFileDialog("image of animation frame");
- try {
- GBA_Image testConverter = processImage(loadedFile);
- // Hextator: See note in the script processor about why
- // the duration is expected to be a short now
- builder.addFrame(
- testConverter, (short)(durationValue.getValue())
- );
- } catch (Exception e2) {
- Common_Dialogs.showGenericErrorDialog(e2.getMessage());
- }
- }
- else if (command.equals("Add Command"))
- {
- builder.addCommand((byte)(commandValue.getValue()));
- }
- else if (command.equals("Add Sound"))
- {
- builder.addSoundCommand((short)(soundValue.getValue()));
- }
- else if (command.equals("Add Mode Terminator"))
- {
- builder.addModeTerminator();
- }
- else if (command.equals("Save Animation..."))
- {
- File tempFile = Common_Dialogs.showSaveFileDialog("animation");
- try {
- if (tempFile != null) {
- builder.create().writeToFile(tempFile);
- }
- }
- catch (Exception e2)
- {
- Common_Dialogs.showStreamErrorDialog();
- }
- }
- else if (command.equals("Load From Script"))
- {
- loadFromScript();
- }
- else if (command.equals("Reset Animation"))
- {
- builder = new Animation_Builder();
- lastPath = "N/A";
- insertThrowableButton.setEnabled(true);
- loopButton.setEnabled(true);
- modeTerminatorButton.setEnabled(false);
- applyButton.setEnabled(false);
- }
- else if (command.equals("Insert Throwable Sprite"))
- {
- // Prompt user for a bitmap
- File loadedFile = Common_Dialogs.showOpenFileDialog("image of throwable sprite");
- try {
- builder.setThrowableSprite(processImage(loadedFile));
- } catch (Exception e3) {
- Common_Dialogs.showGenericErrorDialog(e3.getMessage());
- }
- }
- else if (command.equals("Add Loop Marker"))
- {
- builder.addLoopMarker();
- }
- busy = false;
- update();
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment