package sg.atom2d.tools.map; import javax.swing.*; import java.awt.Graphics.*; import java.io.*; import java.awt.*; import java.util.*; import java.net.*; /** * Stores a set of tiles which can be requested by id number, or name * */ public class GraphicsBank { final static int DEFAULT_TILE_WIDTH = 32; final static int DEFAULT_TILE_HEIGHT = 32; final static String GB_VERSION = "1.0"; final static String DELIM = ","; final static char COMMENT = '#'; final static int ID = 0; final static int PATH = 1; final static int NAME = 2; final static int TYPE = 3; final static int EXTRA = 4; private ArrayList tiles; private ArrayList sprites; private ArrayList changeListeners; File loadedFrom; File baseDirectory; private boolean isUnsaved; Dimension baseTileSize; public GraphicsBank() { tiles = new ArrayList(); sprites = new ArrayList(); changeListeners = new ArrayList(); loadedFrom = null; baseTileSize = new Dimension(DEFAULT_TILE_WIDTH, DEFAULT_TILE_HEIGHT); isUnsaved = true; } public void addSprite(String anmFile) { addSprite(new File(anmFile)); } public void addSprite(File anmFile) { } public void loadTileset(String from) throws FileNotFoundException, IOException { loadTileset(new File(from)); } /** * Load tileset from file. This will combine the tilesets if one has already * been loaded. The most recently loaded tileset file becomes the * "loadedFrom" tileset. * */ public void loadTileset(File from) throws FileNotFoundException, IOException { BufferedReader r; String line; String tokens[]; int id; int lineCount; File tileFile; if (tiles.size() > 0) { isUnsaved = true; } else { isUnsaved = false; } System.out.println(from); baseDirectory = from.getParentFile(); this.loadedFrom = from; lineCount = 0; r = new BufferedReader(new FileReader(from)); while (true) { line = r.readLine(); lineCount++; //stop when no more lines if (line == null) { break; } line = line.trim(); if (line.length() == 0 || line.charAt(0) == COMMENT) { continue; //skip comments and empty lines. } tokens = line.split(DELIM); if (tokens.length < 4) { System.err.println("Could not parse line " + lineCount + ". :"); System.err.println(line); System.err.println("(There are not enough tokens)"); continue; } try { id = Integer.parseInt(tokens[ID].trim()); } catch (Exception e) { System.err.println("Could not parse line " + lineCount + ". :"); System.err.println(line); System.err.println("(The tile id is not a valid number)"); continue; } //get file for image tokens[PATH] = tokens[PATH].trim(); tokens[NAME] = tokens[NAME].trim(); tokens[TYPE] = tokens[TYPE].trim(); tileFile = new File(baseDirectory, tokens[PATH]); //System.out.println("load tile image: "+tileFile); if (!tileFile.exists()) { tileFile = new File(tokens[PATH]); if (tileFile.exists()) { System.err.println("WARNING: file " + tokens[PATH] + " not within the tilemaps working directory"); } else { r.close(); throw new FileNotFoundException("File " + tokens[PATH] + " referenced on line " + lineCount + " of " + from + " could not be found"); } } //System.out.println("New tile: "+id+", name = "+tokens[NAME]); Tile t = null; if (tokens.length > EXTRA) { t = new Tile(id, tileFile.toString(), tokens[NAME].trim(), tokens[TYPE].trim(), tokens[EXTRA].trim()); } else { t = new Tile(id, tileFile.toString(), tokens[NAME], tokens[TYPE]); } tiles.add(t); } } //end loadTileset /** * Save the tileset to the specified file. Will overwrite file if it exists. * */ void saveTileset(File to) throws IOException { File base = to.getParentFile(); PrintWriter w = new PrintWriter(new FileWriter(to)); w.println("# Generated by version " + GB_VERSION + " of GraphicsBank"); w.println("Tile Number, Image file, Tile Name, Type, Extended Info"); System.out.println("Saving " + tiles.size() + " tiles."); Iterator i = tiles.iterator(); while (i.hasNext()) { Tile t = (Tile) i.next(); File tf = new File(t.getPath()).getCanonicalFile(); String relPath = RelativePath.getRelativePath(new File(base.getCanonicalPath()), new File(tf.getCanonicalPath())); w.print("" + t.getNumber() + ", " + relPath + ", " + t.getName() + ", " + t.getType()); if (t.getInfo() != null) { w.println(", " + t.getInfo()); } else { w.println(); } } w.close(); baseDirectory = base; loadedFrom = to; isUnsaved = false; } /** * Get the tileset file this tileset was loaded from. May return NULL if * this is a new tileset that has never been saved. * */ File getFile() { return loadedFrom; } /** * Get a tile by number * */ Tile getTile(int number) { Iterator i = tiles.iterator(); while (i.hasNext()) { Tile t = (Tile) i.next(); if (t.number == number) { return t; } } return null; } /** * Get a tile by name. Case sensitive * */ Tile getTile(String name) { Iterator i = tiles.iterator(); while (i.hasNext()) { Tile t = (Tile) i.next(); if (t.getName().equals(name)) { return t; } } return null; } /** * Rwemove a tile from the graphics bank. Any registered change listeners * will be notified. * */ Tile remove(Tile t) { Tile rm = null; if (tiles.remove(t)) { rm = t; } if (t != null) { fireRemoveEvent(t); isUnsaved = true; } return t; } /** * Add a tile to the graphics bank. Any registered change listeners will be * notified. * */ void add(Tile t) { /* TODO: validate the tile */ tiles.add(t); isUnsaved = true; fireAddEvent(t); } int size() { return tiles.size(); } Dimension getBaseTileSize() { return baseTileSize; } /** * Iterator for tile objects * */ Iterator iterator() { return tiles.iterator(); } /** * Set a global colour adjustment effect for all tiles in the graphics bank. * This will override any individually set effects on all tiles. * */ public void setEffect(float r, float g, float b, float h, float s, float z) { Iterator i = tiles.iterator(); while (i.hasNext()) { ((Tile) (i.next())).adjustRGBHS(r, g, b, h, s, z); } } /** * True if there have been any changes to the tileset since it was last * saved or loaded. * */ public boolean isUnsaved() { if (getFile() == null) { return true; } return isUnsaved; } /** * Get the directory that the tileset file describing this tileset was found * in. * */ File getBaseDirectory() { return baseDirectory; } /** * Get an unused tile number. Returns one more than the highest number used. * */ int getUnusedNumber() { int n = 1; Iterator i = tiles.iterator(); while (i.hasNext()) { Tile t = (Tile) i.next(); if (n <= t.getNumber()) { n = t.getNumber() + 1; } } return n; } /** * Add a GraphicsBankChangeListener to the graphics bank. This listener will * be notified whenever the tileset is changed. * */ void addChangeListener(GraphicsBankChangeListener l) { changeListeners.add(l); } /** * Remove a GraphicsBankChangeListener from the graphics bank. * */ void removeChangeListener(GraphicsBankChangeListener l) { changeListeners.remove(l); } /** * May be called directly, and will cause the tilesetUpdated() method of * every registered GraphicsBankChangeListener object to be called. * */ public void fireChangeEvent() { GraphicsBankChangeListener l; Iterator i = changeListeners.iterator(); while (i.hasNext()) { l = (GraphicsBankChangeListener) i.next(); l.tilesetUpdated(this); } } /** * Called whenever a tile is added using add(). will cause the tileAdded() * method of every registered GraphicsBankChangeListener object to be * called. * */ private void fireAddEvent(Tile t) { System.out.println("Fire add event"); GraphicsBankChangeListener l; Iterator i = changeListeners.iterator(); while (i.hasNext()) { l = (GraphicsBankChangeListener) i.next(); l.tileAdded(this, t); } } /** * Called whenever a tile is removed using remove(). will cause the * tileRemoved() method of every registered GraphicsBankChangeListener * object to be called. * */ private void fireRemoveEvent(Tile t) { GraphicsBankChangeListener l; Iterator i = changeListeners.iterator(); while (i.hasNext()) { l = (GraphicsBankChangeListener) i.next(); l.tileRemoved(this, t); } } } interface GraphicsBankChangeListener { /* Large change happened such as loading a tileset */ public void tilesetUpdated(GraphicsBank bank); /* A single tile was removed */ public void tileRemoved(GraphicsBank bank, Tile removed); /* A single tile was added */ public void tileAdded(GraphicsBank bank, Tile added); }