package com.weem.epicinventor.world; import com.weem.epicinventor.utility.*; import com.weem.epicinventor.world.block.*; import com.weem.epicinventor.*; import java.awt.*; import java.awt.image.*; import java.util.*; import java.io.*; import java.util.jar.*; import javax.imageio.*; import javax.swing.*; import java.awt.color.ColorSpace; import java.util.regex.Pattern; public class WorldImagePainting { private World world; private WorldTown worldTown; private BlockManager blockManager; private static int[] ground; private static int level; private static int wipZMin; private static int wipHeight; private static HashMap groups; private static HashMap blockTypes; private static HashMap groupOverrides; private static HashMap blockTypeOverrides; private static ArrayList caveSpots; private static ArrayList currentLevel; private static ArrayList lastLevel; private static ArrayList noExitImages; private static String config = "WorldImages.dat"; private static String worldImagePath = "/Images/World/"; public WorldImagePainting(World w, WorldTown wt, BlockManager bm, int[] wg) { world = w; worldTown = wt; blockManager = bm; ground = wg; level = 0; groups = new HashMap(); blockTypes = new HashMap(); groupOverrides = new HashMap(); blockTypeOverrides = new HashMap(); caveSpots = new ArrayList(); currentLevel = new ArrayList(); lastLevel = new ArrayList(); noExitImages = new ArrayList(); loadConfig(config); } public void loadConfig(String config) { String line; String type; try { InputStream in = getClass().getResourceAsStream(GameController.CONFIG_DIR + config); BufferedReader br = new BufferedReader(new InputStreamReader(in)); while ((line = br.readLine()) != null) { if (line.length() == 0) { continue; } if (line.startsWith("//")) { continue; } StringTokenizer tokens = new StringTokenizer(line); if (tokens.countTokens() == 1) { } else if (tokens.countTokens() == 3) { type = tokens.nextToken(); if (type.equals("group")) { addGroup(tokens); } else if (type.equals("blockType")) { addBlockType(tokens); } } else if(tokens.countTokens() == 4) { type = tokens.nextToken(); if (type.equals("group")) { addGroupOverride(tokens); } else if (type.equals("blockType")) { addBlockTypeOverride(tokens); } } else { EIError.debugMsg("wrong config argument count", EIError.ErrorLevel.Error); } } in.close(); } catch (Exception e) { System.err.println("Error: " + e.getMessage()); } } public void addGroup(StringTokenizer tokens) { int tokenCount = tokens.countTokens(); String[] settings = new String[tokenCount+1]; String line = ""; for (int i = 0; i < tokenCount; i++) { settings[i] = tokens.nextToken(); line += " " + settings[i]; } EIError.debugMsg("Image Paint Group:" + line, EIError.ErrorLevel.Notice); groups.put(Integer.parseInt(settings[1], 16), settings); } public void addBlockType(StringTokenizer tokens) { int tokenCount = tokens.countTokens(); String[] settings = new String[tokenCount+1]; String line = ""; for (int i = 0; i < tokenCount; i++) { settings[i] = tokens.nextToken(); line += " " + settings[i]; } settings[tokenCount] = Integer.toString(blockManager.getBlockTypeIdByName(settings[0])); EIError.debugMsg("Image Paint Block Type:" + line, EIError.ErrorLevel.Notice); blockTypes.put(Integer.parseInt(settings[1], 16), settings); } public void addGroupOverride(StringTokenizer tokens) { int tokenCount = tokens.countTokens(); String[] settings = new String[tokenCount+1]; String line = ""; for (int i = 0; i < tokenCount; i++) { settings[i] = tokens.nextToken(); line += " " + settings[i]; } EIError.debugMsg("Image Paint Group:" + line, EIError.ErrorLevel.Notice); groupOverrides.put(settings[tokenCount-1]+""+Integer.parseInt(settings[1], 16), settings); } public void addBlockTypeOverride(StringTokenizer tokens) { int tokenCount = tokens.countTokens(); String[] settings = new String[tokenCount+1]; String line = ""; for (int i = 0; i < tokenCount; i++) { settings[i] = tokens.nextToken(); line += " " + settings[i]; } settings[tokenCount] = Integer.toString(blockManager.getBlockTypeIdByName(settings[0])); EIError.debugMsg("Image Paint Block Type:" + line, EIError.ErrorLevel.Notice); blockTypeOverrides.put(settings[tokenCount-1]+""+Integer.parseInt(settings[1], 16), settings); } public int getWipZMin() { return wipZMin; } public int getWipHeight() { return wipHeight; } public BufferedImage[] getPaintImages(String theme) { BufferedImage[] images = null; String line; ArrayList imageNames = new ArrayList(); try { InputStream in = getClass().getResourceAsStream(GameController.CONFIG_DIR + config); BufferedReader br = new BufferedReader(new InputStreamReader(in)); while ((line = br.readLine()) != null) { if (line.length() == 0) { continue; } if (line.startsWith("//")) { continue; } StringTokenizer tokens = new StringTokenizer(line); if (tokens.countTokens() == 1) { String[] nameParts = line.split("/"); if(nameParts[0].equals(theme)) { imageNames.add(nameParts[1]); } } else if (tokens.countTokens() == 3) { } else if(tokens.countTokens() == 4) { } else { EIError.debugMsg("wrong config argument count", EIError.ErrorLevel.Error); } } in.close(); images = new BufferedImage[imageNames.size()]; for(int i = 0; i < imageNames.size(); i++) { images[i] = loadImage(worldImagePath+theme+"/"+imageNames.get(i)); } } catch (Exception e) { System.err.println("Error: " + e.getMessage()); } // try { // String[] imageNames = ResourceList.getResourceListing(WorldImagePainting.class, worldImagePath+theme+"/"); // int count = 0; // for(int i = 0; i < imageNames.length; i++) { // if(!imageNames[i].equals(".svn")) { // count++; // } // } // images = new BufferedImage[count]; // count = 0; // for(int i = 0; i < imageNames.length; i++) { // if(!imageNames[i].equals(".svn")) { // images[count] = loadImage(worldImagePath+theme+"/"+imageNames[i]); // count++; // } // } // } catch (Exception e) { // System.err.println("Error: " + e.getMessage()); // } return images; } public BufferedImage loadImage(String fnm) { BufferedImage im = null; try { im = ImageIO.read(ImageLoader.class.getResource(fnm)); } catch (IOException e) { //System.out.println("Load Image error for " + fnm + ":\n" + e); } return im; } public int getMaxZCaveSpot() { int count = caveSpots.size(); int[] caveSpot; int zMax = 0; int iMax = -1; for(int i = 0; i < count; i++) { caveSpot = (int [])caveSpots.get(i); if(caveSpot[0] > zMax && caveSpot[2] - caveSpot[1] > 3) { zMax = caveSpot[0]; iMax = i; } } return iMax; } public int[][] spawnCaves(int[][] currentBlockArray, int caves, int minX, int maxX, int minZ, int maxZ) { ArrayList maxCaveSpots = new ArrayList(); for(int i = 0; i < caves*3; i++) { int iMax = getMaxZCaveSpot(); int[] caveSpot = null; if(iMax > -1) { caveSpot = (int[])caveSpots.remove(iMax); } if(caveSpot != null) { maxCaveSpots.add(caveSpot); } } int removes = maxCaveSpots.size() - caves; for(int i = 0; i < removes; i++) { maxCaveSpots.remove(Rand.getRange(0, maxCaveSpots.size() - 1)); } for(int i = 0; i < maxCaveSpots.size(); i++) { int[] caveSpot = (int[])maxCaveSpots.get(i); World.direction direction; if(Rand.getFloat() < .5) { direction = World.direction.Left; } else { direction = World.direction.Right; } WorldCavern cavern = new WorldCavern(world, worldTown, 5, 3, 3, ground); currentBlockArray = cavern.carveCave(currentBlockArray, (caveSpot[1]+caveSpot[2])/2, caveSpot[0], minX, minZ, maxX, maxZ, 0.0f, direction); } return currentBlockArray; } public int[][] paintImages(int[][] currentBlockArray, int xMin, int xMax, int zMin, int zMax) { BufferedImage[] images = getPaintImages("Theme1"); int h = images[0].getHeight(); int w = images[0].getWidth(); int i = 0; level = 0; wipZMin = zMin; wipHeight = h; String[] messages = new String[] {"Weem-atizing Elements", "Calculating the 'Epic'", "Removing Mukshapumpa", "Equipping Melvin", "Thanking Testers", "Sneaking up behind you...", "Injecting Bacon" }; boolean closeToGround = false; Game.loadingText = "Making Things Interesting..."; for(int z = zMin; z <= zMax-h; z += h) { if(messages.length > level) { Game.loadingText = messages[level]; } for(int x = xMin; x <= xMax-w; x += w) { closeToGround = closeToGround(x, z, w, h); //System.out.println("closeToGround "+closeToGround); if(!closeToGround) { i = getPaintImageIndex(currentBlockArray, images, x, z, xMin, xMax, (z == zMin)); if(i > -1) { currentBlockArray = paintImage(currentBlockArray, images[i], x, z); } } } //System.out.println("level"); lastLevel = (ArrayList)currentLevel.clone(); currentLevel.clear(); level++; //new level } currentBlockArray = spawnCaves(currentBlockArray, 5, xMin, xMax, zMin, zMax); noExitImages.clear(); return currentBlockArray; } public int getPaintImageIndex(int[][] currentBlockArray, BufferedImage[] images, int x, int z, int xMin, int xMax, boolean bottomLevel) { int[][] pixels = null; int i = -1; int fit = 0; int count = 0; do { i = Rand.getRange(0, images.length-1); pixels = getImagePixels(images[i]); fit = paintImageFit(currentBlockArray, pixels, x, z, xMin, xMax, bottomLevel); count++; } while(fit < 1 && count <= images.length); if(fit == 2 && noExitImages.size() < 1 || count > images.length) { i = -1; } //System.out.println("index: "+i+" fit: "+fit); return i; } public int paintImageFit(int[][] currentBlockArray, int[][] pixels, int x, int z, int xMin, int xMax, boolean bottomLevel) { int fit = 0; int[] exitData = new int[2]; exitData[0] = getExits(pixels); if(ground[x] < z+pixels[0].length*1.5) { boolean exitUp = exitUp(lastLevel, x); if(currentLevel.size() == 0) { if(bottomConnect(currentBlockArray, pixels, x, z)) { if((exitData[0] & Integer.parseInt("1", 16)) > 0) { //System.out.println("top level fit"); fit = 1; } } else if (!exitUp) { //System.out.println("top level not fit"); fit = 2; } } else { int[] leftExits = (int[])currentLevel.get(currentLevel.size()-1); //System.out.println("Close to groud "+exitUp+" "+exitData[0]); if(exitUp && (exitData[0] & Integer.parseInt("1", 16)) > 0) { //System.out.println("exitUp"); fit = 1; } else if(leftConnect(currentBlockArray, pixels, x, z) && (exitData[0] & Integer.parseInt("1", 16)) > 0) { //System.out.println("leftConnect"); fit = 1; } else if(!exitUp && !((leftExits[0] & Integer.parseInt("2", 16)) > 0) && exitData[0] == 0) { //System.out.println("not exitUp"); fit = 1; } } } else if(bottomLevel && (exitData[0] & Integer.parseInt("1", 16)) > 0) { //System.out.println("bottom and up"); fit = 1; } else if(bottomConnect(currentBlockArray, pixels, x, z) && (exitData[0] & Integer.parseInt("3", 16)) > 0) { //System.out.println("bottom connects"); fit = 1; } else { if(leftConnect(currentBlockArray, pixels, x, z)) { //System.out.println("else leftConnect"); fit = 1; } else if(lastLevel.size() > 0) { int[] range = conectionRange(lastLevel, x, pixels.length); if(currentLevel.size() == 0 && range[2] == 1) { //System.out.println("nothing placed and more chances"); fit = 1; } else if(range[2] == 0) { //System.out.println("no more chances"); fit = 2; } } } exitData[1] = x; if(fit == 1) { currentLevel.add(exitData); } if(fit == 2) { exitData[0] = 0; if(noExitImages.size() > 0) { currentLevel.add(exitData); } } return fit; } public int[] conectionRange(ArrayList level, int xStart, int width) { int[] range = new int[3]; int[] current = null; int i = 0; range[0] = range[1] = range[2] = -1; for(; i < level.size(); i++) { current = (int[])level.get(i); if(current[1] >= xStart) { break; } } if(level.size() > i + 2) { current = (int[])level.get(i+1); int[] last = (int[])level.get(i); if((last[0] & Integer.parseInt("2", 16)) > 0 && (current[0] & Integer.parseInt("8", 16)) > 0) { range[0] = range[1] = last[1]; if((current[0] & Integer.parseInt("1", 16)) > 0) { range[2] = 1; } } for(i = i + 2; i < level.size(); i++) { current = (int[])level.get(i); last = (int[])level.get(i-1); if(current[1]-last[1] > width) { break; } if((current[0] & Integer.parseInt("1", 16)) > 0) { range[2] = 1; } if((last[0] & Integer.parseInt("2", 16)) > 0 && (current[0] & Integer.parseInt("8", 16)) > 0) { range[1] = last[1]; } else { break; } } } return range; } public int getExits(int[][] pixels) { int exits = 0; int w = pixels.length; int h = pixels[0].length; for(int i = 3; i < w; i++) { if( isCaveBG(getBlockTypeIdFromPixel(pixels[i][h-1])) && isCaveBG(getBlockTypeIdFromPixel(pixels[i-1][h-1])) && isCaveBG(getBlockTypeIdFromPixel(pixels[i-2][h-1])) ) { exits = exits | 1; } if( isCaveBG(getBlockTypeIdFromPixel(pixels[i][0])) && isCaveBG(getBlockTypeIdFromPixel(pixels[i-1][0])) && isCaveBG(getBlockTypeIdFromPixel(pixels[i-2][0])) ) { exits = exits | 4; } } for(int i = 3; i < h; i++) { if( isCaveBG(getBlockTypeIdFromPixel(pixels[w-1][i])) && isCaveBG(getBlockTypeIdFromPixel(pixels[w-1][i-1])) && isCaveBG(getBlockTypeIdFromPixel(pixels[w-1][i-2])) ) { exits = exits | 2; } if( isCaveBG(getBlockTypeIdFromPixel(pixels[0][i])) && isCaveBG(getBlockTypeIdFromPixel(pixels[0][i-1])) && isCaveBG(getBlockTypeIdFromPixel(pixels[0][i-2])) ) { exits = exits | 8; } } if(exits == 0) { noExitImages.add(pixels); } return exits; } public boolean leftConnect(int[][] currentBlockArray, int[][] pixels, int x, int z) { boolean connects = false; boolean imageConnects = false; for(int i = 3; i < pixels[0].length && !connects; i++) { if( isCaveBG(currentBlockArray[x-1][z+i]) && isCaveBG(currentBlockArray[x-1][z+i-1]) && isCaveBG(currentBlockArray[x-1][z+i-2]) && isCaveBG(getBlockTypeIdFromPixel(pixels[0][i])) && isCaveBG(getBlockTypeIdFromPixel(pixels[0][i-1])) && isCaveBG(getBlockTypeIdFromPixel(pixels[0][i-2])) ) { imageConnects = true; } } if(imageConnects) { int[] currentExits = null; int[] nextExits = null; int lastX = x; for(int i = currentLevel.size()-1; i > 0; i--) { currentExits = (int [])currentLevel.get(i); nextExits = (int [])currentLevel.get(i); if((currentExits[0] & Integer.parseInt("4", 16)) > 0) { if(exitUp(lastLevel, currentExits[1])) { connects = true; } } //if next tile is not a tile distance away if(nextExits[1] != (lastX-pixels.length)) { break; } //if tile does not connects to the left if(!((currentExits[0] & Integer.parseInt("8", 16)) > 0 && (nextExits[0] & Integer.parseInt("8", 16)) > 0)) { break; } lastX = currentExits[1]; } } return connects; } public boolean exitUp(ArrayList level, int x) { boolean exitUp = false; int[] exits = null; for(int i = 0; i < level.size(); i++) { exits = (int [])level.get(i); if(exits[1] == x) { if((exits[0] & Integer.parseInt("1", 16)) > 0) { exitUp = true; } } } return exitUp; } public boolean bottomConnect(int[][] currentBlockArray, int[][] pixels, int x, int z) { boolean connects = false; for(int i = 3; i < pixels.length && !connects; i++) { if( isCaveBG(currentBlockArray[x+i][z-1]) && isCaveBG(currentBlockArray[x+i-1][z-1]) && isCaveBG(currentBlockArray[x+i-2][z-1]) && isCaveBG(getBlockTypeIdFromPixel(pixels[i][0])) && isCaveBG(getBlockTypeIdFromPixel(pixels[i-1][0])) && isCaveBG(getBlockTypeIdFromPixel(pixels[i-2][0])) ) { connects = true; } } return connects; } public boolean isCaveBG(int blockTypeId) { boolean isCave = false; if(blockTypeId > 0) { BlockType bt = blockManager.getBlockTypeById((short)blockTypeId); if(bt != null && bt.isBackground()) { isCave = true; } } return isCave; } public boolean closeToGround(int currentX, int currentZ, int width, int hight) { boolean closeToGround = false; for(int x = currentX; x < currentX + width; x++) { if(currentZ+hight-10 > ground[x]) { closeToGround = true; } } return closeToGround; } public int[][] paintImage(int[][] currentBlockArray, BufferedImage image, int xStart, int zStart) { int[][] pixels = getImagePixels(image); int[] caveSpot = new int[3]; caveSpot[0] = -1; caveSpot[1] = -1; caveSpot[2] = -1; for(int z = 0; z < pixels[0].length; z++) { for(int x = 0; x < pixels.length; x++) { if(zStart+z+20 < ground[xStart+x]) { currentBlockArray[xStart+x][zStart+z] = paintBlock(currentBlockArray[xStart+x][zStart+z], pixels[x][z]); if(z == pixels[0].length - 2 && isCaveBG(currentBlockArray[xStart+x][zStart+z])) { if(caveSpot[0] == -1) { caveSpot[0] = zStart+z; caveSpot[1] = xStart+x; //caveSpot[2] = xStart+x+4; } if(pixels[x+1][z] != 0 && caveSpot[2] == -1 && !isCaveBG(pixels[x+1][z])) { caveSpot[2] = xStart+x; } } } } } if(caveSpot[0] > 0) { caveSpots.add(caveSpot); } return currentBlockArray; } public int getBlockTypeIdFromPixel(int imagePixel) { int blockTypeId = -1; String[] line = (String[])groups.get(imagePixel); if(line != null) { int newBlockType = blockManager.getRandomIdByGroup(line[0]); if(newBlockType > 0) { blockTypeId = newBlockType; } } line = (String[])blockTypes.get(imagePixel); if(line != null) { int newBlockType = Integer.parseInt(line[line.length - 1]); if(newBlockType > 0) { blockTypeId = newBlockType; } } int blockTypeOverrideId = getBlockTypeOverrideIdFromPixel(imagePixel); if(blockTypeOverrideId > 0) { blockTypeId = blockTypeOverrideId; } return blockTypeId; } public int getBlockTypeOverrideIdFromPixel(int imagePixel) { int blockTypeId = -1; String[] line = (String[])groupOverrides.get((level+1)+""+imagePixel); if(line != null) { int newBlockType = blockManager.getRandomIdByGroup(line[0]); if(newBlockType > 0) { blockTypeId = newBlockType; } } line = (String[])blockTypeOverrides.get((level+1)+""+imagePixel); if(line != null) { int newBlockType = Integer.parseInt(line[line.length - 1]); if(newBlockType > 0) { blockTypeId = newBlockType; } } return blockTypeId; } public int paintBlock(int currentBlock, int imagePixel) { int newBlockType = getBlockTypeIdFromPixel(imagePixel); if(newBlockType != -1) { currentBlock = newBlockType; } return currentBlock; } public int[][] getImagePixels(BufferedImage image) { int w = image.getWidth(null); int h = image.getHeight(null); int[] tmpPixels = new int[w * h]; image.getRGB(0, 0, w, h, tmpPixels, 0, w); int[][] pixels = new int[w][h]; for(int y = 0; y < h; y++) { for(int x = 0; x < w; x++) { pixels[x][h-1-y] = tmpPixels[x+y*w] & Integer.parseInt("FFFFFF", 16); } } return pixels; } }