package net.fe; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.ObjectInputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.Scanner; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.json.simple.JSONValue; import org.json.simple.parser.ParseException; import org.lwjgl.opengl.GL11; import org.newdawn.slick.Color; import org.newdawn.slick.openal.Audio; import org.newdawn.slick.openal.AudioLoader; import org.newdawn.slick.opengl.Texture; import org.newdawn.slick.util.ResourceLoader; import chu.engine.AnimationData; import chu.engine.anim.BitmapFont; import net.fe.builderStage.TeamNameInput; import net.fe.unit.Item; import net.fe.unit.Unit; import net.fe.unit.Weapon; import org.lwjgl.input.Keyboard; import java.io.File; import java.util.Properties; // TODO: Auto-generated Javadoc /** * The Class FEResources. */ public class FEResources { /** The search folders. */ private static String[] searchFolders = {"battle_anim", "battle_anim/static", "map_mugshots", "gui", "map_anim"}; /** The audio. */ private static HashMap<String, Audio> audio; /** The textures. */ private static HashMap<String, AnimationData> textures; /** The bitmap fonts. */ private static HashMap<String, BitmapFont> bitmapFonts; static { audio = new HashMap<String, Audio>(); textures = new HashMap<String, AnimationData>(); bitmapFonts = new HashMap<String, BitmapFont>(); } /** * Gets the texture. * * @param string the string * @return the texture */ public static Texture getTexture(String string) { if(string.contains("phantom") && string.contains("mugshot")) return getTextureData("phantom_mugshot").getTexture(); return getTextureData(string).getTexture(); } /** * Checks for texture. * * @param string the string * @return true, if successful */ public static boolean hasTexture(String string){ return textures.containsKey(string); } /** * Load resources. */ public static void loadResources() { try { //Load bitmap fonts loadBitmapFonts(); // Textures textures.put("whoops", new AnimationData("res/whoops.png")); loadTextures(); //load audio audio.put("miss", AudioLoader.getAudio("WAV", ResourceLoader.getResourceAsStream("res/sfx/miss.wav"))); } catch (IOException e) { int max = GL11.glGetInteger(GL11.GL_MAX_TEXTURE_SIZE); System.out.println(max); e.printStackTrace(); } System.gc(); } /** * Gets the map texture. * * @param name the name * @return the map texture */ public static AnimationData getMapTexture(String name){ AnimationData t = textures.get(name); if(t!=null) return t; System.out.println("Warn:" + name + " not explicitly defined"); for(String loc: searchFolders){ try{ AnimationData txt = new AnimationData("res/" + loc + "/" + name + ".png", 96, 24, 4, 4, 4, 4, 0, null, null); textures.put(name, txt); return txt; } catch (Exception e){ } } return textures.get("whoops"); } /** * Load textures. */ private static void loadTextures() { long startTime = System.nanoTime(); // TODO Load textures from JSON InputStream file = ResourceLoader.getResourceAsStream("res/resources.json"); Scanner in = new Scanner(file); StringBuilder sb = new StringBuilder(); while(in.hasNextLine()) { sb.append(in.nextLine()); } String json = sb.toString(); JSONObject resources = null; try { resources = (JSONObject) JSONValue.parseWithException(json); } catch (ParseException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } JSONArray txArray = (JSONArray) resources.get("textures"); LoadStage.setMaximum(txArray.size()); for(Object obj : txArray) { JSONObject texture = (JSONObject) obj; String name = (String)texture.get("name"); String path = (String)texture.get("path"); Number width = (Number)texture.get("width"); Number height = (Number)texture.get("height"); Number frames = (Number)texture.get("frames"); Number columns = (Number)texture.get("columns"); Number freeze = (Number)texture.get("freeze"); Number offsetX = (Number)texture.get("offsetX"); Number offsetY = (Number)texture.get("offsetY"); Number speed = (Number)texture.get("speed"); Number shakeFrames = (Number)texture.get("shakeFrames"); Number shakeIntensity = (Number)texture.get("shakeIntensity"); Boolean stop = (Boolean)texture.get("stop"); JSONArray hitArray = (JSONArray) texture.get("hitframes"); JSONArray audioArray = (JSONArray) texture.get("soundMap"); HashMap<Integer, String> audioMap = new HashMap<Integer, String>(); String blendModeName = (String)texture.get("blend"); int[] hitframes; if(hitArray != null) { hitframes = new int[hitArray.size()]; for(int i=0; i<hitframes.length; i++) { hitframes[i] = ((Number)hitArray.get(i)).intValue(); } } else { hitframes = new int[0]; } if(audioArray != null) { for(Object obj2 : audioArray) { JSONObject audio = (JSONObject) obj2; audioMap.put(((Number)audio.get("frame")).intValue(), (String)audio.get("sound")); } } AnimationData data; if(width == null) { data = new AnimationData(path); } else { data = new AnimationData(path, width.intValue(), height.intValue(), frames.intValue(), columns.intValue(), offsetX.intValue(), offsetY.intValue(), freeze.intValue(), hitframes, audioMap); } if(speed != null) data.speed = speed.floatValue(); if(shakeFrames != null) data.shakeFrames = shakeFrames.intValue(); if(shakeIntensity != null) data.shakeIntensity = shakeIntensity.intValue(); if(stop != null) data.stop = stop.booleanValue(); data.blendModeName = blendModeName; textures.put(name, data); if((System.nanoTime() - startTime)/1000000.0f > 100){ LoadStage.update(textures.size()); LoadStage.render(); } } in.close(); } /** * Gets the bitmap font. * * @param name the name * @return the bitmap font */ public static BitmapFont getBitmapFont(String name) { return bitmapFonts.get(name); } /** * Load bitmap fonts. */ public static void loadBitmapFonts() { Scanner in = new Scanner(ResourceLoader.getResourceAsStream("res/fonts/fonts.txt")); while(in.hasNextLine()) { String line = in.nextLine(); if(line.startsWith("#")) continue; if(line.startsWith("define")) { String name = line.split(":")[1]; String texName = in.nextLine(); char[] chars = in.nextLine().toCharArray(); int height = Integer.parseInt(in.nextLine()); int spacing = Integer.parseInt(in.nextLine()); char[] widths = in.nextLine().toCharArray(); BitmapFont font = new BitmapFont(texName); font.setHeight(height); font.setSpacing(spacing); int pos = 0; for(int i=0; i<chars.length; i++) { int width = Integer.parseInt(widths[i]+""); font.put(chars[i], pos, width); pos += width; } bitmapFonts.put(name, font); System.out.println(name+"(bitmap font) loaded"); } } in.close(); } /** * Gets the texture data. * * @param string the string * @return the texture data */ public static AnimationData getTextureData(String string) { AnimationData t = textures.get(string); if(t != null) { return t; } else { //try to get it, in case we forgot System.err.println("Warn: " + string + " not explicitly defined"); for(String loc: searchFolders){ if(ResourceLoader.resourceExists("res/" + loc + "/" + string + ".png")){ AnimationData txt = new AnimationData("res/" + loc + "/" + string + ".png"); textures.put(string, txt); return txt; } } return textures.get("whoops"); } } /** * Gets the audio. * * @param name the name * @return the audio */ public static Audio getAudio(String name) { Audio a = audio.get(name); if(a == null) { // System.err.println("Warn: " + name + " not explicitly defined"); try{ Audio b = AudioLoader.getAudio("WAV", ResourceLoader.getResourceAsStream("res/sfx/"+name+".wav")); audio.put(name, b); return b; } catch (Exception e){ return null; } } else { return a; } } /** Returns the default properties */ private static Properties getDefaultProperties() { final Properties defaultProps = new Properties(); // keybindings defaultProps.setProperty("Z", "Z"); defaultProps.setProperty("X", "X"); defaultProps.setProperty("C", "C"); defaultProps.setProperty("D", "D"); defaultProps.setProperty("RETURN", "RETURN"); defaultProps.setProperty("LEFT", "LEFT"); defaultProps.setProperty("RIGHT", "RIGHT"); defaultProps.setProperty("UP", "UP"); defaultProps.setProperty("DOWN", "DOWN"); // other defaultProps.setProperty("VOLUME","1.0"); defaultProps.setProperty("SCALE","1.0"); defaultProps.setProperty("AUTOCURSOR", "START"); defaultProps.setProperty("FOG COLOR", "DAY"); defaultProps.setProperty("ACTUAL ODDS", "FALSE"); defaultProps.setProperty("TARGETFPS", "60"); // music defaultProps.setProperty("CURING","curing"); defaultProps.setProperty("DEFENSE","defense"); defaultProps.setProperty("END","end"); defaultProps.setProperty("ENEMY","enemy"); defaultProps.setProperty("FIGHT","fight"); defaultProps.setProperty("MAIN","main"); defaultProps.setProperty("OVERWORLD","overworld"); defaultProps.setProperty("PREPARATIONS","preparations"); defaultProps.setProperty("LORD","lord"); return defaultProps; } /** The set of user settings. */ private static Properties prop; /** * Gets the properties. * * @return the properties */ //takes in a key such as Keyboard.KEY_Z and returns the corresponding key the user presses private static Properties getProperties() { if (prop == null) { prop = new Properties(); final File path = new File("app.config"); try { final boolean isPatch = path.exists(); //should probably also have a check for directory && !f.isDirectory() //but unless the user creates it, that won't be true. No clear way of handling it. if (path.exists()) { try(InputStream in = new FileInputStream(path)) { prop.load(in); } } else { //make file and populate it path.createNewFile(); } final Properties defaultProps = getDefaultProperties(); for (String key : prop.stringPropertyNames()) { defaultProps.remove(key); } for (String key : defaultProps.stringPropertyNames()) { prop.setProperty(key, defaultProps.getProperty(key)); } if (! defaultProps.isEmpty()) { try(OutputStream out = new FileOutputStream(path, isPatch)) { if (isPatch) {out.write('\n');} defaultProps.store(out, (isPatch ? "---Patch---" : "---Initial Configuration---")); } } } catch (IOException e){ e.printStackTrace(); prop = getDefaultProperties(); } } return prop; } /** * Stores a set of properties to disk * * @return true if the files were written to disk */ public static boolean writeProperties(java.util.Map<String, String> newProperties) { Properties p = FEResources.getProperties(); p.putAll(newProperties); final File path = new File("app.config"); try(OutputStream out = new FileOutputStream(path, false)) { p.store(out, "---Updated---"); return true; } catch (IOException e) { return false; } } /** * Gets the audio volume. * * @return the audio volume */ public static float getAudioVolume(){ String volumeStr = getProperties().getProperty("VOLUME"); float volume = Float.parseFloat(volumeStr); return volume; } public static String getAudioSetting(String setting) throws Exception{ String audioName = ""; try{ audioName = getProperties().getProperty(setting); }catch(Exception e){ throw e; } return audioName; } public static boolean getActualOdds() { return ((String) prop.get("ACTUAL ODDS")).equalsIgnoreCase("TRUE"); } public static enum AutoCursor { START(true, true), START_LOCAL(true, false), OFF(false, false); public final boolean applyAtStartOfLocalTurn; public final boolean applyAtStartOfOtherTurn; private AutoCursor(boolean applyAtStartOfLocalTurn, boolean applyAtStartOfOtherTurn) { this.applyAtStartOfLocalTurn = applyAtStartOfLocalTurn; this.applyAtStartOfOtherTurn = applyAtStartOfOtherTurn; } } /** * Returns the autocursor setting; whether to move the cursor to the player's lord at the start of the turn. */ public static AutoCursor getAutoCursor() { String propStr = getProperties().getProperty("AUTOCURSOR"); if ("start".equalsIgnoreCase(propStr)) { return AutoCursor.START; } else if ("startLocal".equalsIgnoreCase(propStr)) { return AutoCursor.START_LOCAL; } else if ("off".equalsIgnoreCase(propStr)) { return AutoCursor.OFF; } else { return AutoCursor.OFF; } } /** * Gets the window scale. * * @return the window scale */ public static float getWindowScale(){ String scaleStr = getProperties().getProperty("SCALE"); float scale = Float.parseFloat(scaleStr); return scale; } public static enum FogColor { DAY(new Color(1f,1f,1f, 0.5f)), NIGHT(new Color(0f,0f,0.1f, 0.5f)); public final Color color; private FogColor(Color color) { this.color = color; } } /** * Returns the color to use when drawing fog */ public static FogColor getFogColor() { String propStr = getProperties().getProperty("FOG COLOR"); if ("day".equalsIgnoreCase(propStr)) { return FogColor.DAY; } else if ("night".equalsIgnoreCase(propStr)) { return FogColor.NIGHT; } else { return FogColor.DAY; } } public static int getTargetFPS() { return Integer.parseInt(getProperties().getProperty("TARGETFPS")); } /** * Gets the key mapped. * * @param internalKey the internal key * @return the key mapped */ public static int getKeyMapped(int internalKey){ //NOTE: LevelEditorStage does not use this. So its controls are still hard-coded. // However the level editor is not part of the user-facing game, so doesn't need them at the moment. // To fix that, this method should be changed so that instead of using "internalKey" as a keyboard // it should take in an Enum or const that tells the meaning, not the key // for example "back" instead of "key_z" // right now this method has no way of knowing if Z is used for something other than backing out // therefore, right now it has to assume Z is always back out when translating String mappedKey = getProperties().getProperty(Keyboard.getKeyName(internalKey)); if(mappedKey!=null && !mappedKey.equals("")){ return Keyboard.getKeyIndex(mappedKey); } //other controls: //left/right/up/down //backspace //delete //enter return internalKey; } /** * Gets the key mapped name. * * @param internalKeyName the internal key name * @return the key mapped name */ public static String getKeyMappedName(String internalKeyName){ if(internalKeyName.toUpperCase().equals("ENTER")){ internalKeyName = "RETURN"; } int key = Keyboard.getKeyIndex(internalKeyName.toUpperCase()); int mappedKey = getKeyMapped(key); String mappedName = Keyboard.getKeyName(mappedKey); //this might seem redundant, but it's to allow code using the string "Enter" to map to the key "Return" //which then maps the key according to the bindings (possibly to something else) //if it's still "return" we want this translated back to "enter" if(mappedName.equals("RETURN")){ return "ENTER"; } return mappedName; } }