/*******************************************************************************
* Rhythos Editor is a game editor and project management tool for making RPGs on top of the Rhythos Game system.
*
* Copyright (C) 2013 David Maletz
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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, see <http://www.gnu.org/licenses/>.
******************************************************************************/
package mrpg.editor.resource;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JTextField;
import mrpg.editor.AutoTileEditor;
import mrpg.editor.MapEditor;
import mrpg.editor.TilesetViewer;
import mrpg.editor.WorkspaceBrowser;
import mrpg.world.AutoTilemap;
import mrpg.world.Tilemap;
public class AutoTile extends TileResource implements ActionListener {
private static final long serialVersionUID = 3981925226292874481L;
public static final String EXT = "atm", TYPE = "at"; private static final short VERSION=1;
public static final String ADD_AUTOTILE="set-tileset";
private Tilemap autotile; private ImageResource image;
private AnimationSet animation; private int aid; private AutotileFormat format;
private JMenuItem add_autotile = MapEditor.createMenuItemIcon("Toggle Autotile", ADD_AUTOTILE, this);
public AutoTile(File f, MapEditor e){super(f, e);}
public void contextMenu(JPopupMenu menu){
WorkspaceBrowser browser = editor.getBrowser(); menu.add(add_autotile); menu.add(browser.properties); menu.addSeparator();
}
public String getType(){return TYPE;}
public short getVersion(){return VERSION;}
public JDialog getProperties(){return new Properties(this);}
public boolean edit(){editor.getTilesetViewer().toggleAutoTile(autotile, WorkspaceBrowser.getProject(this)); return true;}
public ImageResource getImage(){return image;}
public Tilemap getTilemap(){return autotile;}
public void actionPerformed(ActionEvent e) {edit();}
private boolean active = false;
public void remove(boolean delete) throws Exception {
super.remove(delete);
active = editor.getTilesetViewer().removeAutoTile(autotile); MapEditor.instance.refreshTilesets();
}
public void addToProject(Project p, boolean changeProject) throws Exception {
super.addToProject(p, changeProject);
if(changeProject){
image = (ImageResource)p.getById(image.getType(), image.getId());
if(animation != null) try{animation = (AnimationSet)p.getById(AnimationSet.TYPE, animation.getId());}catch(Exception ex){animation = null;}
}
}
public void writeInner(DataOutputStream out) throws Exception {
super.writeInner(out); ImageResource.write(out, image); out.writeLong(format.getId()); autotile.write(out);
out.writeLong((animation==null)?0:animation.getId()); out.writeShort(aid);
}
public void readInner(DataInputStream in) throws Exception {
super.readInner(in); Project p = WorkspaceBrowser.getProject(this); image = ImageResource.read(in, p);
format = (AutotileFormat)p.getById(AutotileFormat.TYPE, in.readLong());
autotile = new AutoTilemap(in, format.getFormat(), image.getImage(), this, p.tile_size);
long asid = in.readLong(); AnimationSet ani = null;
if(asid != 0) try{ani = (AnimationSet)p.getById(AnimationSet.TYPE, asid);}catch(Exception ex){}
animation = ani; aid = in.readShort();
}
public void deferredRead(File f) throws Exception {
super.deferredRead(f);
if(active){active = false; editor.getTilesetViewer().addAutoTile(autotile, WorkspaceBrowser.getProject(this));}
}
protected void read(File f) throws Exception {MapEditor.deferRead(this, MapEditor.DEF_TILEMAP);}
public boolean isCompatible(Project p){
try{p.getById(image.getType(), image.getId()); return super.isCompatible(p);}catch(Exception e){return false;}
}
public void copyAssets(Project p) throws Exception {
if(!image.isCompatible(p)) image.copyAssets(p);
p.editor.getBrowser().addResource(Resource.readFile(image.copy(p.getFile(), p, false), p.editor), p);
}
public static AutoTile createAutoTile(Resource parent, MapEditor e, Project p) throws Exception {
String dir = parent.getFile().toString();
File f = new File(dir,"New AutoTile"+"."+EXT);
AutoTile ret = new AutoTile(f, e); ret.newId(p); ret._setName(null);
ret.properties(); if(!((Properties)ret.properties).updated) throw new Exception();
ret.addToProject(p,false); return ret;
}
public static AutoTile createAutoTile(Resource parent, MapEditor e, Project p, AutotileFormat fmt, String name, ImageResource im) throws Exception {
String dir = parent.getFile().toString();
File f = new File(dir,name+"."+EXT);
AutoTile ret = new AutoTile(f, e); ret.newId(p); ret.format = fmt;
ret.image = im; ret.autotile = new AutoTilemap(ret.format.getFormat(), im.getImage(), ret, p.tile_size);
parent.add(ret); ret.save(); ret.addToProject(p,false); return ret;
}
public Animation getAnimation(){
if(aid < 0 || animation == null || aid >= animation.numAnimations()) return null;
return animation.getAnimation(aid);
}
private static class Properties extends TypedResource.Properties {
private static final long serialVersionUID = -4987880557990107307L;
private static final String SET_F = "set_f", SET_A = "set_a", CLEAR_A = "clear_a";
private AnimationSet animation; private JTextField ani_label, fmt_label; private AutotileFormat format;
private AutoTileEditor editor; private ImageResource image; private Tilemap tilemap; private JComboBox preview_ani;
public Properties(AutoTile t){super(t, "AutoTile Properties");}
public void addControls(JPanel settings){
JPanel inner = new JPanel(); inner.setBorder(BorderFactory.createTitledBorder("Format"));
JPanel p = new JPanel(); fmt_label = new JTextField("", 15); fmt_label.setEditable(false); p.add(fmt_label);
JButton set = new JButton("Set"); set.setActionCommand(SET_F); set.addActionListener(this); p.add(set);
inner.add(p); settings.add(inner);
inner = new JPanel(); inner.setBorder(BorderFactory.createTitledBorder("Auto Tile"));
editor = new AutoTileEditor(getTileSize());
p = new JPanel(); p.add(editor); p.setBorder(BorderFactory.createLoweredBevelBorder()); inner.add(p);
set = new JButton("Set"); set.setActionCommand(MapEditor.SET); set.addActionListener(this); inner.add(set);
settings.add(inner);
inner = new JPanel(); inner.setBorder(BorderFactory.createTitledBorder("Animation")); inner.setLayout(new BoxLayout(inner, BoxLayout.Y_AXIS));
p = new JPanel(); ani_label = new JTextField("", 15); ani_label.setEditable(false); p.add(ani_label);
set = new JButton("Set"); set.setActionCommand(SET_A); set.addActionListener(this); p.add(set);
JButton clear = new JButton("Clear"); clear.setActionCommand(CLEAR_A); clear.addActionListener(this); p.add(clear);
inner.add(p); p = new JPanel(); p.add(new JLabel("Use: ")); preview_ani = new JComboBox(); preview_ani.setEnabled(false);
preview_ani.addActionListener(this); preview_ani.setPreferredSize(ani_label.getPreferredSize()); p.add(preview_ani); inner.add(p);
settings.add(inner);
}
private int getTileSize(){Project p = resource.getProject(); if(p == null) return TilesetViewer.TILE_SIZE; else return p.tile_size;}
public void updateControls(){
AutoTile autotile = (AutoTile)resource; image = autotile.image; format = autotile.format;
if(format == null) fmt_label.setText(""); else fmt_label.setText(format.getName());
tilemap = autotile.autotile; editor.setTilemap(tilemap); setAnimation(autotile.animation, autotile.aid);
}
public void acceptControls() throws Exception {
if(format == null){
JOptionPane.showMessageDialog(resource.editor, "You must specify an Auto Tile Format for the auto tile.", "Auto Tile Creation Error", JOptionPane.ERROR_MESSAGE);
throw new Exception();
} else if(image == null || tilemap == null){
JOptionPane.showMessageDialog(resource.editor, "You must specify an image for the auto tile.", "Auto Tile Creation Error", JOptionPane.ERROR_MESSAGE);
throw new Exception();
} AutoTile autotile = (AutoTile)resource; autotile.image = image; autotile.format = format;
autotile.autotile = tilemap; autotile.animation = animation; autotile.aid = preview_ani.getSelectedIndex();
MapEditor.instance.refreshTilesets();
}
public boolean saveOnEdit(){return true;}
public void actionPerformed(ActionEvent e) {
if(e.getSource() == preview_ani){
if(preview_ani.isEnabled()) updateAnimation(); return;
}
String command = e.getActionCommand();
if(command == MapEditor.SET){
if(format == null){
JOptionPane.showMessageDialog(this, "You must choose an Auto Tile Format before setting an image.", "Cannot Set Image", JOptionPane.ERROR_MESSAGE); return;
} AutoTile autotile = (AutoTile)resource; Project p = autotile.getProject();
if(p == null){JOptionPane.showMessageDialog(this, "Tileset is not added to any project, no images to load...", "Cannot Find Images", JOptionPane.ERROR_MESSAGE); return;}
ImageResource im = ImageResource.choose(p, image);
if(im != null){
try{
tilemap = new AutoTilemap(format.getFormat(), im.getImage(), autotile, p.tile_size);
image = im; editor.setTilemap(tilemap);
}catch(Exception ex){JOptionPane.showMessageDialog(autotile.editor, "Unable to create AutoTile: "+ex.getMessage(), "AutoTile Creation Error", JOptionPane.ERROR_MESSAGE);}
}
} else if(command == SET_F){
Project p = resource.getProject(); AutotileFormat f = AutotileFormat.choose(p, format);
if(f != null){
try{
if(image != null){
tilemap = new AutoTilemap(f.getFormat(), image.getImage(), (AutoTile)resource, p.tile_size);
editor.setTilemap(tilemap);
} format = f; fmt_label.setText(format.getName());
} catch(Exception ex){JOptionPane.showMessageDialog(resource.editor, "The selected format can not render the selected image: "+ex.getMessage(), "Set Format Error", JOptionPane.ERROR_MESSAGE);}
}
} else if(command == SET_A){
AnimationSet a = AnimationSet.choose(getProject(), animation); if(a != null) setAnimation(a,0);
} else if(command == CLEAR_A){
setAnimation(null,0);
} else super.actionPerformed(e);
}
private Project getProject(){
Project p = resource.getProject();
if(p == null){JOptionPane.showMessageDialog(this, "Tileset is not added to any project, no images to load...", "Cannot Find Images", JOptionPane.ERROR_MESSAGE); return null;}
return p;
}
private void setAnimation(AnimationSet a, int aid){
animation = a; if(animation != null && animation.numAnimations() > 0){
ani_label.setText(animation.getName()); preview_ani.setEnabled(false);
DefaultComboBoxModel model = (DefaultComboBoxModel)preview_ani.getModel();
model.removeAllElements(); for(Animation ani : animation) model.addElement(ani);
preview_ani.setSelectedIndex(aid); preview_ani.setEnabled(true);
} else {ani_label.setText(""); preview_ani.setEnabled(false); ((DefaultComboBoxModel)preview_ani.getModel()).removeAllElements();}
updateAnimation();
}
private void updateAnimation(){
editor.setAnimation(animation, preview_ani.getSelectedIndex());
}
}
public String getExt(){return EXT;}
public static void register() throws Exception {
Resource.register("Auto Tile Files", AutoTile.EXT, AutoTile.TYPE, AutoTile.class);
Resource.register("Auto Tile Format Files", AutotileFormat.EXT, AutotileFormat.TYPE, AutotileFormat.class);
Folder.new_options.addMenu("Map", Map.MAP).
addItem("Auto Tile", "database", KeyEvent.VK_T, ActionEvent.CTRL_MASK | ActionEvent.SHIFT_MASK, new CreateAutoTileAction());
}
private static class CreateAutoTileAction implements ActionListener {
public void actionPerformed(ActionEvent e){
MapEditor.instance.getBrowser().addAutoTile();
}
}
}