diff --git a/src/dk/itu/mario/level/Level.java b/src/dk/itu/mario/level/Level.java index e93c8d8..ba01a01 100644 --- a/src/dk/itu/mario/level/Level.java +++ b/src/dk/itu/mario/level/Level.java @@ -5,212 +5,231 @@ import java.io.*; import dk.itu.mario.MarioInterface.LevelInterface; import dk.itu.mario.engine.sprites.SpriteTemplate; +public class Level implements LevelInterface { -public class Level implements LevelInterface -{ + protected static final byte BLOCK_EMPTY = (byte) (0 + 1 * 16); + protected static final byte BLOCK_POWERUP = (byte) (4 + 2 + 1 * 16); + protected static final byte BLOCK_COIN = (byte) (4 + 1 + 1 * 16); + protected static final byte GROUND = (byte) (1 + 9 * 16); + protected static final byte ROCK = (byte) (9 + 0 * 16); + protected static final byte COIN = (byte) (2 + 2 * 16); - protected static final byte BLOCK_EMPTY = (byte) (0 + 1 * 16); - protected static final byte BLOCK_POWERUP = (byte) (4 + 2 + 1 * 16); - protected static final byte BLOCK_COIN = (byte) (4 + 1 + 1 * 16); - protected static final byte GROUND = (byte) (1 + 9 * 16); - protected static final byte ROCK = (byte) (9 + 0 * 16); - protected static final byte COIN = (byte) (2 + 2 * 16); + protected static final byte CANNON_TOP = (byte) (14 + 0 * 16); + protected static final byte CANNON_MIDDLE = (byte) (14 + 1 * 16); + protected static final byte CANNON_BOTTOM = (byte) (14 + 2 * 16); + protected static final byte LEFT_GRASS_EDGE = (byte) (0 + 9 * 16); + protected static final byte RIGHT_GRASS_EDGE = (byte) (2 + 9 * 16); + protected static final byte RIGHT_UP_GRASS_EDGE = (byte) (2 + 8 * 16); + protected static final byte LEFT_UP_GRASS_EDGE = (byte) (0 + 8 * 16); + protected static final byte LEFT_POCKET_GRASS = (byte) (3 + 9 * 16); + protected static final byte RIGHT_POCKET_GRASS = (byte) (3 + 8 * 16); - protected static final byte LEFT_GRASS_EDGE = (byte) (0+9*16); - protected static final byte RIGHT_GRASS_EDGE = (byte) (2+9*16); - protected static final byte RIGHT_UP_GRASS_EDGE = (byte) (2+8*16); - protected static final byte LEFT_UP_GRASS_EDGE = (byte) (0+8*16); - protected static final byte LEFT_POCKET_GRASS = (byte) (3+9*16); - protected static final byte RIGHT_POCKET_GRASS = (byte) (3+8*16); + protected static final byte HILL_FILL = (byte) (5 + 9 * 16); + protected static final byte HILL_LEFT = (byte) (4 + 9 * 16); + protected static final byte HILL_RIGHT = (byte) (6 + 9 * 16); + protected static final byte HILL_TOP = (byte) (5 + 8 * 16); + protected static final byte HILL_TOP_LEFT = (byte) (4 + 8 * 16); + protected static final byte HILL_TOP_RIGHT = (byte) (6 + 8 * 16); - protected static final byte HILL_FILL = (byte) (5 + 9 * 16); - protected static final byte HILL_LEFT = (byte) (4 + 9 * 16); - protected static final byte HILL_RIGHT = (byte) (6 + 9 * 16); - protected static final byte HILL_TOP = (byte) (5 + 8 * 16); - protected static final byte HILL_TOP_LEFT = (byte) (4 + 8 * 16); - protected static final byte HILL_TOP_RIGHT = (byte) (6 + 8 * 16); + protected static final byte HILL_TOP_LEFT_IN = (byte) (4 + 11 * 16); + protected static final byte HILL_TOP_RIGHT_IN = (byte) (6 + 11 * 16); - protected static final byte HILL_TOP_LEFT_IN = (byte) (4 + 11 * 16); - protected static final byte HILL_TOP_RIGHT_IN = (byte) (6 + 11 * 16); + protected static final byte TUBE_TOP_LEFT = (byte) (10 + 0 * 16); + protected static final byte TUBE_TOP_RIGHT = (byte) (11 + 0 * 16); - protected static final byte TUBE_TOP_LEFT = (byte) (10 + 0 * 16); - protected static final byte TUBE_TOP_RIGHT = (byte) (11 + 0 * 16); + protected static final byte TUBE_SIDE_LEFT = (byte) (10 + 1 * 16); + protected static final byte TUBE_SIDE_RIGHT = (byte) (11 + 1 * 16); - protected static final byte TUBE_SIDE_LEFT = (byte) (10 + 1 * 16); - protected static final byte TUBE_SIDE_RIGHT = (byte) (11 + 1 * 16); + // The level's width and height + protected int width; + protected int height; - //The level's width and height - protected int width; - protected int height; + // This map of WIDTH * HEIGHT that contains the level's design + private byte[][] map; - //This map of WIDTH * HEIGHT that contains the level's design - private byte[][] map; + // This is a map of WIDTH * HEIGHT that contains the placement and type + // enemies + private SpriteTemplate[][] spriteTemplates; - //This is a map of WIDTH * HEIGHT that contains the placement and type enemies - private SpriteTemplate[][] spriteTemplates; + // These are the place of the end of the level + protected int xExit; + protected int yExit; - //These are the place of the end of the level - protected int xExit; - protected int yExit; + public Level() { - public Level(){ + } - } + public Level(int width, int height) { + this.width = width; + this.height = height; - public Level(int width, int height) - { - this.width = width; - this.height = height; + xExit = 10; + yExit = 10; + map = new byte[width][height]; + spriteTemplates = new SpriteTemplate[width][height]; + } - xExit = 10; - yExit = 10; - map = new byte[width][height]; - spriteTemplates = new SpriteTemplate[width][height]; - } + public static void loadBehaviors(DataInputStream dis) throws IOException { + dis.readFully(Level.TILE_BEHAVIORS); + } - public static void loadBehaviors(DataInputStream dis) throws IOException - { - dis.readFully(Level.TILE_BEHAVIORS); - } + public static void saveBehaviors(DataOutputStream dos) throws IOException { + dos.write(Level.TILE_BEHAVIORS); + } - public static void saveBehaviors(DataOutputStream dos) throws IOException - { - dos.write(Level.TILE_BEHAVIORS); - } + /** + * Clone the level data so that we can load it when Mario die + */ + public Level clone() throws CloneNotSupportedException { - /** - *Clone the level data so that we can load it when Mario die - */ - public Level clone() throws CloneNotSupportedException { + Level clone = new Level(width, height); - Level clone=new Level(width, height); + clone.map = new byte[width][height]; + clone.spriteTemplates = new SpriteTemplate[width][height]; + clone.xExit = xExit; + clone.yExit = yExit; - clone.map = new byte[width][height]; - clone.spriteTemplates = new SpriteTemplate[width][height]; - clone.xExit = xExit; - clone.yExit = yExit; + for (int i = 0; i < map.length; i++) + for (int j = 0; j < map[i].length; j++) { + clone.map[i][j] = map[i][j]; + clone.spriteTemplates[i][j] = spriteTemplates[i][j]; + } - for (int i = 0; i < map.length; i++) - for (int j = 0; j < map[i].length; j++) { - clone.map[i][j]= map[i][j]; - clone.spriteTemplates[i][j] = spriteTemplates[i][j]; - } + return clone; - return clone; + } - } + public void tick() { + } - public void tick(){ } + public byte getBlockCapped(int x, int y) { + if (x < 0) + x = 0; + if (y < 0) + y = 0; + if (x >= width) + x = width - 1; + if (y >= height) + y = height - 1; + return map[x][y]; + } - public byte getBlockCapped(int x, int y) - { - if (x < 0) x = 0; - if (y < 0) y = 0; - if (x >= width) x = width - 1; - if (y >= height) y = height - 1; - return map[x][y]; - } + public byte getBlock(int x, int y) { + if (x < 0) + x = 0; + if (y < 0) + return 0; + if (x >= width) + x = width - 1; + if (y >= height) + y = height - 1; + return map[x][y]; + } - public byte getBlock(int x, int y) - { - if (x < 0) x = 0; - if (y < 0) return 0; - if (x >= width) x = width - 1; - if (y >= height) y = height - 1; - return map[x][y]; - } + public void setBlock(int x, int y, byte b) { + if (x < 0) + return; + if (y < 0) + return; + if (x >= width) + return; + if (y >= height) + return; + map[x][y] = b; + } - public void setBlock(int x, int y, byte b) - { - if (x < 0) return; - if (y < 0) return; - if (x >= width) return; - if (y >= height) return; - map[x][y] = b; - } + public boolean isBlocking(int x, int y, float xa, float ya) { + byte block = getBlock(x, y); - public boolean isBlocking(int x, int y, float xa, float ya) - { - byte block = getBlock(x, y); + boolean blocking = ((TILE_BEHAVIORS[block & 0xff]) & BIT_BLOCK_ALL) > 0; + blocking |= (ya > 0) + && ((TILE_BEHAVIORS[block & 0xff]) & BIT_BLOCK_UPPER) > 0; + blocking |= (ya < 0) + && ((TILE_BEHAVIORS[block & 0xff]) & BIT_BLOCK_LOWER) > 0; - boolean blocking = ((TILE_BEHAVIORS[block & 0xff]) & BIT_BLOCK_ALL) > 0; - blocking |= (ya > 0) && ((TILE_BEHAVIORS[block & 0xff]) & BIT_BLOCK_UPPER) > 0; - blocking |= (ya < 0) && ((TILE_BEHAVIORS[block & 0xff]) & BIT_BLOCK_LOWER) > 0; + return blocking; + } - return blocking; - } + public SpriteTemplate getSpriteTemplate(int x, int y) { + if (x < 0) + return null; + if (y < 0) + return null; + if (x >= width) + return null; + if (y >= height) + return null; + return spriteTemplates[x][y]; + } - public SpriteTemplate getSpriteTemplate(int x, int y) - { - if (x < 0) return null; - if (y < 0) return null; - if (x >= width) return null; - if (y >= height) return null; - return spriteTemplates[x][y]; - } + public void setSpriteTemplate(int x, int y, SpriteTemplate spriteTemplate) { + if (x < 0) + return; + if (y < 0) + return; + if (x >= width) + return; + if (y >= height) + return; + spriteTemplates[x][y] = spriteTemplate; + } - public void setSpriteTemplate(int x, int y, SpriteTemplate spriteTemplate) - { - if (x < 0) return; - if (y < 0) return; - if (x >= width) return; - if (y >= height) return; - spriteTemplates[x][y] = spriteTemplate; - } + public SpriteTemplate[][] getSpriteTemplate() { + return this.spriteTemplates; + } - public SpriteTemplate[][] getSpriteTemplate(){ - return this.spriteTemplates; - } - - public void resetSpriteTemplate(){ - for (int i = 0; i < spriteTemplates.length; i++) { + public void resetSpriteTemplate() { + for (int i = 0; i < spriteTemplates.length; i++) { for (int j = 0; j < spriteTemplates[i].length; j++) { SpriteTemplate st = spriteTemplates[i][j]; - if(st != null) + if (st != null) st.isDead = false; } } - } + } - - public void print(byte[][] array){ - for (int i = 0; i < array.length; i++) { + public void print(byte[][] array) { + for (int i = 0; i < array.length; i++) { for (int j = 0; j < array[i].length; j++) { System.out.print(array[i][j]); } System.out.println(); } - } + } + public byte[][] getMap() { return map; } + public SpriteTemplate[][] getSpriteTemplates() { return spriteTemplates; } + public int getxExit() { // TODO Auto-generated method stub return xExit; } + public int getyExit() { // TODO Auto-generated method stub return yExit; } + public int getWidth() { // TODO Auto-generated method stub return width; } + public int getHeight() { // TODO Auto-generated method stub return height; } - public String getName() { // TODO Auto-generated method stub return ""; } - } diff --git a/src/dk/itu/mario/level/PCGLevel.java b/src/dk/itu/mario/level/PCGLevel.java index 94ddaa9..3994f26 100644 --- a/src/dk/itu/mario/level/PCGLevel.java +++ b/src/dk/itu/mario/level/PCGLevel.java @@ -7,7 +7,6 @@ import java.util.Random; import dk.itu.mario.MarioInterface.GamePlay; import dk.itu.mario.MarioInterface.LevelInterface; import dk.itu.mario.engine.DataRecorder; -import dk.itu.mario.engine.sprites.Enemy; import dk.itu.mario.engine.sprites.SpriteTemplate; import dk.itu.mario.level.grammar.LevelGrammar; import dk.itu.mario.level.grammar.LevelGrammarFactory; @@ -16,6 +15,12 @@ import dk.itu.mario.level.matcher.ArchetypeMatcher; import dk.itu.mario.level.matcher.ProfileMatcher; public class PCGLevel extends Level { + public static double POWERUP_PROBABILITY = .1; + public static double BLOCKS_PROBABILITY = .3; + public static double COINS_PROBABILITY = .5; + public static int COIN_REWARD = 1; + public static int POWERUP_REWARD = 2; + public static boolean TESTING = true; public static long lastSeed; private static Random levelSeedRandom = new Random(); @@ -121,30 +126,50 @@ public class PCGLevel extends Level { int length = 0; if (TESTING) { - difficulty = 6; + difficulty = 10; + int minElements = 5; + int maxLen; + int elementsSoFar = 0; - length = buildStraight(0, width - 64, true); - length += buildFreebie(length, width - 64 - length); + length = buildStraight(0, width - 64, false); - length += buildBowlingAlley(length, width - 64 - length, - SpriteTemplate.ARMORED_TURTLE); - length += buildFreebie(length, width - 64 - length); - - length += buildLemmingTrap(length, width - 64 - length); - length += buildFreebie(length, width - 64 - length); - - length += buildPlatformJump(length, width - 64 - length); - length += buildFreebie(length, width - 64 - length); - - length += buildMaze(length, width - 64 - length); - length += buildFreebie(length, width - 64 - length); - - length += buildPipeJump(length, width - 64 - length); - length += buildFreebie(length, width - 64 - length); - - // create all of the medium sections while (length < width - 64) { - length += buildStraight(length, width - length, true); + maxLen = elementsSoFar < minElements ? (width - 64 - length) + / (minElements - elementsSoFar) : width - 64 - length; + + switch (random.nextInt(9)) { + case 0: + length += buildStraight(length, maxLen, true); + break; + case 1: + length += buildFreebie(length, maxLen); + break; + case 2: + length += buildBowlingAlley(length, maxLen); + break; + case 3: + length += buildLemmingTrap(length, maxLen); + break; + case 4: + length += buildPipeJump(length, maxLen); + break; + case 5: + length += buildPlatformJump(length, maxLen); + break; + case 6: + length += buildCoinDive(length, maxLen); + break; + case 7: + length += buildCannonLine(length, maxLen); + break; + case 8: + length += buildSinglePit(length, maxLen); + break; + default: + length += buildMaze(length, maxLen); + } + + elementsSoFar++; } } @@ -158,7 +183,8 @@ public class PCGLevel extends Level { System.out.println("Building for: " + lcomp); switch (lctype) { case FLAT: - length += buildStraight(length, lcomp.getEnd(), true); + length += buildStraight(length, lcomp.getEnd(), + random.nextBoolean()); break; case PIPE_JUMP: length += buildPipeJump(length, width - 64 - length); @@ -196,11 +222,100 @@ public class PCGLevel extends Level { fillEndPiece(length, floor); } - private int buildFreebie(int xo, int maxLength) { - if (maxLength >= 5) { + private int buildSinglePit(int xo, int maxLength) { + if (maxLength >= 13) { + int length = 13; + int floor = height - 1 - random.nextInt(4); + + for (int x = 0; x < length; x++) { + if (x != 5 && x != 6 && x != 7) { + for (int y = floor; y < height; y++) { + setBlock(xo + x, y, Level.GROUND); + } + } + + if ((x >= 2 && x <= 4) || (x >= 8 && x <= 10)) { + setBlock(xo + x, floor - 1, Level.ROCK); + + if (x == 3 || x == 4 || x == 8 || x == 9) { + setBlock(xo + x, floor - 2, Level.ROCK); + } + + if (x == 4 || x == 8) { + setBlock(xo + x, floor - 3, Level.ROCK); + } + } + } + + return length; + } + + return 0; + } + + private int buildCannonLine(int xo, int maxLength) { + if (maxLength >= 6) { int floor = height - 1 - random.nextInt(4); - for (int x = 0; x < 5; x++) { + int length = 6; + + for (int x = 0; x < length; x++) { + for (int y = floor; y < height; y++) { + setBlock(xo + x, y, Level.GROUND); + } + + if (x == 3) { + setBlock(xo + x, floor - 1, Level.CANNON_MIDDLE); + setBlock(xo + x, floor - 2, Level.CANNON_TOP); + setBlock(xo + x, floor - 3, + shouldAddChallenge() ? Level.CANNON_TOP + : Level.CANNON_MIDDLE); + setBlock(xo + x, floor - 4, Level.CANNON_TOP); + } + } + + return length; + } + return 0; + } + + private int buildCoinDive(int xo, int maxLength) { + if (maxLength >= 18) { + int length = 18; + + int floor = height - 1 - random.nextInt(4); + + for (int x = 0; x < length; x++) { + for (int y = floor; y < height; y++) { + setBlock(xo + x, y, Level.GROUND); + } + + if (x > 2 && x < 6) { + setBlock(xo + x, floor - 3, Level.BLOCK_EMPTY); + } else if (x > 2 && x < 11) { + setBlock(xo + x, floor - 5, Level.BLOCK_EMPTY); + } else if (x == 11 || x == 12) { + setBlock(xo + x, floor - 6, Level.COIN); + } else if (x == 13) { + setBlock(xo + x, floor - 5, Level.COIN); + } else if (x == 14) { + setBlock(xo + x, floor - 4, Level.COIN); + } else if (x == 15) { + setBlock(xo + x, floor - 3, Level.COIN); + } + } + + return length; + } + + return 0; + + } + + private int buildFreebie(int xo, int maxLength) { + if (maxLength >= 9) { + int floor = height - 1 - random.nextInt(4); + for (int x = 0; x < 9; x++) { for (int y = 0; y < height; y++) { if (y >= floor) { setBlock(xo + x, y, GROUND); @@ -208,6 +323,46 @@ public class PCGLevel extends Level { } } + if (random.nextBoolean()) { + setBlock(xo + 1, floor - 1, Level.BLOCK_EMPTY); + setBlock(xo + 7, floor - 1, Level.BLOCK_POWERUP); + + setSpriteTemplate(xo + 6, floor - 1, new SpriteTemplate( + SpriteTemplate.GREEN_TURTLE, false)); + } + + else { + int powerupLoc = random.nextInt(5); + + setBlock(xo + 2, floor - 3, + powerupLoc == 0 ? Level.BLOCK_POWERUP + : Level.BLOCK_COIN); + setBlock(xo + 3, floor - 3, + powerupLoc == 1 ? Level.BLOCK_POWERUP + : Level.BLOCK_COIN); + setBlock(xo + 4, floor - 3, + powerupLoc == 2 ? Level.BLOCK_POWERUP + : Level.BLOCK_COIN); + setBlock(xo + 5, floor - 3, + powerupLoc == 3 ? Level.BLOCK_POWERUP + : Level.BLOCK_COIN); + setBlock(xo + 6, floor - 3, + powerupLoc == 4 ? Level.BLOCK_POWERUP + : Level.BLOCK_COIN); + } + + return 9; + } + + else if (maxLength >= 5) { + + int floor = height - 1 - random.nextInt(4); + for (int x = 0; x < 5; x++) { + for (int y = floor; y < height; y++) { + setBlock(xo + x, y, GROUND); + } + } + if (random.nextBoolean()) { setBlock(xo, floor - 1, Level.BLOCK_EMPTY); setBlock(xo + 4, floor - 1, Level.BLOCK_POWERUP); @@ -225,37 +380,85 @@ public class PCGLevel extends Level { return 0; } - private int buildBowlingAlley(int xo, int maxLength, int enemyType) { - if (maxLength >= 26 - && (enemyType == SpriteTemplate.ARMORED_TURTLE || enemyType == SpriteTemplate.GREEN_TURTLE)) { + private int buildBowlingAlley(int xo, int maxLength) { + if (maxLength >= 26) { + int floor = height - 1 - random.nextInt(4); + int enemyType = shouldAddChallenge() ? (shouldAddChallenge() ? SpriteTemplate.ARMORED_TURTLE + : SpriteTemplate.GREEN_TURTLE) + : SpriteTemplate.GOOMPA; + int reward = shouldAddReward(); + boolean arc = random.nextBoolean(); int numEnemies = 0; for (int i = 0; i < 10; i++) { numEnemies += shouldAddChallenge() ? 1 : 0; } // Create the pit. - setBlock(xo, this.height - 2, Level.GROUND); - setBlock(xo, this.height - 1, Level.GROUND); + for (int y = floor - 1; y < height; y++) { + setBlock(xo, y, Level.GROUND); + setBlock(xo + 1, y, Level.GROUND); + } - setBlock(xo + 1, this.height - 1, Level.GROUND); - setBlock(xo + 1, this.height - 2, Level.GROUND); + for (int y = floor; y < height; y++) { + setBlock(xo + 2, y, Level.GROUND); + setBlock(xo + 3, y, Level.GROUND); + setBlock(xo + 4, y, Level.GROUND); + } - setBlock(xo + 2, this.height - 1, Level.GROUND); - setBlock(xo + 3, this.height - 1, Level.GROUND); - setBlock(xo + 4, this.height - 1, Level.GROUND); - - setSpriteTemplate(xo + 2, this.height - 2, new SpriteTemplate( + setSpriteTemplate(xo + 2, floor - 1, new SpriteTemplate( SpriteTemplate.RED_TURTLE, false)); for (int x = 5; x < 26; x++) { - setBlock(xo + x, this.height - 1, Level.GROUND); - setBlock(xo + x, this.height - 2, Level.GROUND); - setBlock(xo + x, this.height - 3, Level.GROUND); + for (int y = floor - 3; y < height; y++) { + setBlock(xo + x, y, Level.GROUND); + } + + if (arc && reward == 1 && x >= 11 && x <= 23) { + if (x == 15) { + setBlock(xo + x, floor - 6, Level.COIN); + } + + else if (x == 16) { + setBlock(xo + x, floor - 7, Level.COIN); + } + + else if (x == 18) { + setBlock(xo + x, floor - 8, Level.COIN); + } + + else if (x == 19) { + setBlock(xo + x, floor - 8, Level.COIN); + } + + else if (x == 20) { + setBlock(xo + x, floor - 8, Level.COIN); + } + + else if (x == 22) { + setBlock(xo + x, floor - 7, Level.COIN); + } + + else if (x == 23) { + setBlock(xo + x, floor - 6, Level.COIN); + } + } + + else if (!arc && reward == 1 && x >= 10 && x <= 20) { + setBlock(xo + x, floor - 6, Level.COIN); + } + + else if (reward == 2 && x >= 13 && x <= 17) { + setBlock( + xo + x, + floor - 6, + (random.nextDouble() <= POWERUP_PROBABILITY) ? Level.BLOCK_POWERUP + : Level.BLOCK_COIN); + } if (x >= 26 - numEnemies) { - setSpriteTemplate(xo + x, this.height - 4, - new SpriteTemplate(enemyType, false)); + setSpriteTemplate(xo + x, floor - 4, new SpriteTemplate( + enemyType, false)); } } @@ -267,25 +470,42 @@ public class PCGLevel extends Level { private int buildLemmingTrap(int xo, int maxLength) { if (maxLength >= 14) { + int floor = height - 1 - random.nextInt(4); int enemyType = shouldAddChallenge() ? (shouldAddChallenge() ? SpriteTemplate.ARMORED_TURTLE : SpriteTemplate.GREEN_TURTLE) : SpriteTemplate.GOOMPA; boolean flying = shouldAddChallenge() && shouldAddChallenge() && shouldAddChallenge(); + int reward = shouldAddReward(); for (int x = 0; x < 18; x++) { if (x > 5) { - for (int y = 0; y < 5; y++) { - setBlock(xo + x, this.height - 1 - y, Level.GROUND); + for (int y = floor - 4; y < height; y++) { + setBlock(xo + x, y, Level.GROUND); + } + } + + else { + for (int y = floor; y < height; y++) { + setBlock(xo + x, y, Level.GROUND); } - } else { - setBlock(xo + x, this.height - 1 - ((x > 5) ? 6 : 0), - Level.GROUND); } if (x > 6 && x % 2 == 0) { - setSpriteTemplate(xo + x, this.height - 6, - new SpriteTemplate(enemyType, flying)); + setSpriteTemplate(xo + x, floor - 5, new SpriteTemplate( + enemyType, flying)); + } + + if (reward == 1 && x >= 7 && x <= 16) { + setBlock(xo + x, floor - 7, Level.COIN); + } + + else if (reward == 2 && x >= 10 && x <= 13) { + setBlock( + xo + x, + floor - 7, + random.nextDouble() < POWERUP_PROBABILITY ? Level.BLOCK_POWERUP + : Level.BLOCK_COIN); } } return 18; @@ -324,25 +544,6 @@ public class PCGLevel extends Level { fixWalls(); } - private void addEnemyLine(int x0, int x1, int y) { - for (int x = x0; x < x1; x++) { - if (random.nextInt(35) < difficulty + 1) { - int type = random.nextInt(4); - - if (difficulty < 1) { - type = Enemy.ENEMY_GOOMBA; - } else if (difficulty < 3) { - type = random.nextInt(3); - } - - setSpriteTemplate(x, y, - new SpriteTemplate(type, - random.nextInt(35) < difficulty)); - ENEMIES++; - } - } - } - private void blockify(Level level, boolean[][] blocks, int width, int height) { int to = 0; if (type == LevelInterface.TYPE_CASTLE) { @@ -442,6 +643,19 @@ public class PCGLevel extends Level { return random.nextInt(11) + 1 <= difficulty; } + private int shouldAddReward() { + double guess = random.nextDouble(); + + if (guess < COINS_PROBABILITY) { + return 1; + } else if (guess < COINS_PROBABILITY + BLOCKS_PROBABILITY) { + return 2; + } else { + return 0; + } + + } + private int buildMaze(int xo, int maxLength) { if (maxLength >= 19) { @@ -515,9 +729,11 @@ public class PCGLevel extends Level { // skipDown = (skipDown && (x == str.len - 2)) // || (str.len >= 5 && x == (str.len / 2)); midLine = (str.len >= 5 && x == (str.len / 2) - 1); - addEnemy = (str.len >= 5 && x == (str.len / 2)); stretchEnd = (x == str.len - 1); + addEnemy = !midLine && !stretchEnd + && (random.nextDouble() < .25); + if // ((stretchEnd && nxt != null && nxt.lvl != // MazeLevel.BOT) // || @@ -564,11 +780,11 @@ public class PCGLevel extends Level { : SpriteTemplate.GREEN_TURTLE) : SpriteTemplate.GOOMPA; - switch (str.lvl) { - case TOP: + switch (random.nextInt(3)) { + case 0: heightMod = 8; break; - case MID: + case 1: heightMod = 5; break; default: @@ -577,7 +793,7 @@ public class PCGLevel extends Level { setSpriteTemplate(xo + soFar + x, this.height - heightMod, new SpriteTemplate(enemyType, - shouldAddChallenge())); + false)); } } @@ -594,65 +810,81 @@ public class PCGLevel extends Level { } private int buildPipeJump(int xo, int maxLength) { - int numPipes = 4; - int length = numPipes * 2; + int length = 0; int lastHeight = 4; int localHeight; + int midFloor; int pipeHeight; int gap = 0; + boolean space; + boolean deadGaps = shouldAddChallenge(); - while (length > maxLength) { - numPipes--; - length = numPipes * 2; + int numPipes; + for (numPipes = 0; shouldAddChallenge(); numPipes++) { } - if (length == 0) { - return length; - } + localHeight = random.nextInt(2) + 1; + loop: for (int i = 0; i < numPipes; i++) { + space = (length + 2) <= maxLength; - for (int i = 0; i < numPipes && length < maxLength; i++) { - length += random.nextInt(4); - } + if (space) { + while (Math.abs(localHeight - lastHeight) > 3) { + localHeight += localHeight > lastHeight ? -1 : 1; + } - if (length > maxLength) { - length = maxLength; - } + lastHeight = localHeight; - for (int soFar = 0; numPipes > 0; numPipes--) { - localHeight = (soFar == 0) ? random.nextInt(2) + 4 : random - .nextInt(7) + 4; + pipeHeight = localHeight > 5 ? 4 + random + .nextInt(localHeight - 4) : 4; - while (Math.abs(localHeight - lastHeight) > 3) { - localHeight += localHeight > lastHeight ? -1 : 1; - } + for (int y = 0; y < localHeight; y++) { + setBlock(xo + length, this.height - 1 - y, Level.GROUND); + setBlock(xo + length + 1, this.height - 1 - y, Level.GROUND); - lastHeight = localHeight; - pipeHeight = localHeight > 5 ? 4 + random.nextInt(localHeight - 4) - : 4; + if (y == localHeight - 1) { + setBlock(xo + length, this.height - 1 - y, + Level.TUBE_TOP_LEFT); + setBlock(xo + length + 1, this.height - 1 - y, + Level.TUBE_TOP_RIGHT); - for (int y = 0; y < localHeight; y++) { - setBlock(xo + soFar, this.height - 1 - y, Level.GROUND); - setBlock(xo + soFar + 1, this.height - 1 - y, Level.GROUND); + if (shouldAddChallenge()) { + setSpriteTemplate(xo + length, this.height - y, + new SpriteTemplate( + SpriteTemplate.JUMP_FLOWER, false)); + } + } else if (y > localHeight - pipeHeight) { + setBlock(xo + length, this.height - 1 - y, + Level.TUBE_SIDE_LEFT); + setBlock(xo + length + 1, this.height - 1 - y, + Level.TUBE_SIDE_RIGHT); + } + } - if (y == localHeight - 1) { - setBlock(xo + soFar, this.height - 1 - y, - Level.TUBE_TOP_LEFT); - setBlock(xo + soFar + 1, this.height - 1 - y, - Level.TUBE_TOP_RIGHT); - } else if (y > localHeight - pipeHeight) { - setBlock(xo + soFar, this.height - 1 - y, - Level.TUBE_SIDE_LEFT); - setBlock(xo + soFar + 1, this.height - 1 - y, - Level.TUBE_SIDE_RIGHT); + length += 2; + + localHeight = random.nextInt(7) + 4; + + midFloor = localHeight - (random.nextInt(4) + 1); + if (midFloor <= 0) { + midFloor = 1; + } + + for (gap = 0; gap < 4 && length + gap <= maxLength + && shouldAddChallenge(); gap++) { + + if (!deadGaps) { + for (int y = 0; y < midFloor; y++) { + setBlock(xo + length, this.height - 1 - y, + Level.GROUND); + } + } + length++; } } - gap = random.nextInt(4); - while (soFar + gap + 2 > length && gap >= 0) { - gap--; + else { + break loop; } - - soFar += (2 + gap); } return length; @@ -665,7 +897,13 @@ public class PCGLevel extends Level { for (gapLength = 1; shouldAddChallenge() && gapLength < 4; gapLength++) { } - int numPlatforms = random.nextInt((maxLength - 3) / (4 + gapLength)); + int maxNumPlatforms = (maxLength - 3) / (4 + gapLength); + + if (maxNumPlatforms == 0) { + return 0; + } + + int numPlatforms = random.nextInt(maxNumPlatforms); if (numPlatforms > 1) { boolean found = false; @@ -676,6 +914,8 @@ public class PCGLevel extends Level { int heightMod = 0; int lastHeightMod = 0; int enemyType; + int reward; + LevelComponent.PlatformLevel hold; jumps.add(LevelComponent.PlatformLevel.BOT); @@ -738,7 +978,8 @@ public class PCGLevel extends Level { lastHeightMod = heightMod; } - switch (jumps.get(x)) { + hold = jumps.get(x); + switch (hold) { case TOP: heightMod = 12; break; @@ -766,10 +1007,10 @@ public class PCGLevel extends Level { if (shouldAddChallenge()) { - enemyType = shouldAddChallenge() ? (shouldAddChallenge() ? (shouldAddChallenge() ? SpriteTemplate.ARMORED_TURTLE - : SpriteTemplate.RED_TURTLE) - : SpriteTemplate.GREEN_TURTLE) - : SpriteTemplate.GOOMPA; + enemyType = random.nextBoolean() ? SpriteTemplate.RED_TURTLE + : (shouldAddChallenge() ? (shouldAddChallenge() ? SpriteTemplate.ARMORED_TURTLE + : SpriteTemplate.GREEN_TURTLE) + : SpriteTemplate.GOOMPA); setSpriteTemplate( xo + length + 3, @@ -780,6 +1021,33 @@ public class PCGLevel extends Level { || enemyType != SpriteTemplate.RED_TURTLE)); } + reward = shouldAddReward(); + if (reward == COIN_REWARD + && hold != LevelComponent.PlatformLevel.TOP) { + setBlock(xo + length, this.height - heightMod - 3, + Level.COIN); + setBlock(xo + length + 1, this.height - heightMod - 3, + Level.COIN); + setBlock(xo + length + 2, this.height - heightMod - 3, + Level.COIN); + setBlock(xo + length + 3, this.height - heightMod - 3, + Level.COIN); + } + + else if (reward == POWERUP_REWARD + && hold != LevelComponent.PlatformLevel.TOP) { + setBlock( + xo + length + 1, + this.height - heightMod - 3, + random.nextDouble() < POWERUP_PROBABILITY ? Level.BLOCK_POWERUP + : Level.BLOCK_COIN); + setBlock( + xo + length + 2, + this.height - heightMod - 3, + random.nextDouble() < POWERUP_PROBABILITY ? Level.BLOCK_POWERUP + : Level.BLOCK_COIN); + } + length += 4 + gapLength; } } @@ -787,16 +1055,17 @@ public class PCGLevel extends Level { return length; } - private int buildStraight(int xo, int maxLength, boolean safe) { - int length = random.nextInt(10) + 2; + private int buildStraight(int xo, int maxLength, boolean allowEnemies) { + int length = random.nextInt(15) + 2; - if (safe) - length = 10 + random.nextInt(5); + // if (safe) + // length = 10 + random.nextInt(5); if (length > maxLength) length = maxLength; int floor = height - 1 - random.nextInt(4); + int reward = shouldAddReward(); // runs from the specified x position to the length of the segment for (int x = xo; x < xo + length; x++) { @@ -807,70 +1076,181 @@ public class PCGLevel extends Level { } } - if (!safe) { - if (length > 5) { - decorate(xo, xo + length, floor); + if (shouldAddChallenge() && allowEnemies) { + int enemyType = shouldAddChallenge() ? (shouldAddChallenge() ? (shouldAddChallenge() ? (shouldAddChallenge() + || (reward > 0 && length >= 5) ? SpriteTemplate.ARMORED_TURTLE + : SpriteTemplate.CANNON_BALL) + : SpriteTemplate.RED_TURTLE) + : SpriteTemplate.GREEN_TURTLE) + : SpriteTemplate.GOOMPA; + + if (enemyType == SpriteTemplate.CANNON_BALL) { + int height = random.nextInt(4) + 1; + + if (height == 1) { + setBlock(xo + (length / 2), floor - 1, Level.CANNON_TOP); + } + + else if (height == 2) { + setBlock(xo + (length / 2), floor - 1, Level.CANNON_MIDDLE); + setBlock(xo + (length / 2), floor - 2, Level.CANNON_TOP); + } + + else if (height == 3) { + setBlock(xo + (length / 2), floor - 1, Level.CANNON_BOTTOM); + setBlock(xo + (length / 2), floor - 2, Level.CANNON_MIDDLE); + setBlock(xo + (length / 2), floor - 3, Level.CANNON_TOP); + } + + else { + setBlock(xo + (length / 2), floor - 1, Level.CANNON_BOTTOM); + setBlock(xo + (length / 2), floor - 2, Level.CANNON_BOTTOM); + setBlock(xo + (length / 2), floor - 3, Level.CANNON_MIDDLE); + setBlock(xo + (length / 2), floor - 4, Level.CANNON_TOP); + } + } + + else { + setSpriteTemplate(xo + (length / 2), floor - 1, + new SpriteTemplate(enemyType, shouldAddChallenge())); } } + if (reward > 0) { + if (length >= 13) { + setBlock(xo + (length - 11), floor - 3, Level.COIN); + setBlock(xo + (length - 10), floor - 4, Level.COIN); + setBlock(xo + (length - 8), floor - 5, Level.COIN); + setBlock(xo + (length - 7), floor - 5, Level.COIN); + setBlock(xo + (length - 6), floor - 5, Level.COIN); + setBlock(xo + (length - 4), floor - 4, Level.COIN); + setBlock(xo + (length - 3), floor - 3, Level.COIN); + } + + else if (length >= 7) { + int start = length / 2; + boolean coins = (reward == 1); + + setBlock( + xo + (start - 2), + floor - 3, + coins ? Level.COIN + : random.nextDouble() < POWERUP_PROBABILITY ? Level.BLOCK_POWERUP + : Level.BLOCK_COIN); + setBlock( + xo + (start - 1), + floor - 3, + coins ? Level.COIN + : random.nextDouble() < POWERUP_PROBABILITY ? Level.BLOCK_POWERUP + : Level.BLOCK_COIN); + setBlock( + xo + start, + floor - 3, + coins ? Level.COIN + : random.nextDouble() < POWERUP_PROBABILITY ? Level.BLOCK_POWERUP + : Level.BLOCK_COIN); + setBlock( + xo + (start + 2), + floor - 3, + coins ? Level.COIN + : random.nextDouble() < POWERUP_PROBABILITY ? Level.BLOCK_POWERUP + : Level.BLOCK_COIN); + setBlock( + xo + (start + 1), + floor - 3, + coins ? Level.COIN + : random.nextDouble() < POWERUP_PROBABILITY ? Level.BLOCK_POWERUP + : Level.BLOCK_COIN); + } + + else if (length >= 5) { + int start = length / 2; + boolean coins = (reward == 1); + + setBlock( + xo + (start - 1), + floor - 3, + coins ? Level.COIN + : random.nextDouble() < POWERUP_PROBABILITY ? Level.BLOCK_POWERUP + : Level.BLOCK_COIN); + setBlock( + xo + start, + floor - 3, + coins ? Level.COIN + : random.nextDouble() < POWERUP_PROBABILITY ? Level.BLOCK_POWERUP + : Level.BLOCK_COIN); + setBlock( + xo + (start + 1), + floor - 3, + coins ? Level.COIN + : random.nextDouble() < POWERUP_PROBABILITY ? Level.BLOCK_POWERUP + : Level.BLOCK_COIN); + } + } + // if (!safe) { + // if (length > 5) { + // decorate(xo, xo + length, floor); + // } + // } + return length; } - private void decorate(int xStart, int xLength, int floor) { - // if its at the very top, just return - if (floor < 1) - return; - - // boolean coins = random.nextInt(3) == 0; - boolean rocks = true; - - // add an enemy line above the box - addEnemyLine(xStart + 1, xLength - 1, floor - 1); - - int s = random.nextInt(4); - int e = random.nextInt(4); - - if (floor - 2 > 0) { - if ((xLength - 1 - e) - (xStart + 1 + s) > 1) { - for (int x = xStart + 1 + s; x < xLength - 1 - e; x++) { - setBlock(x, floor - 2, COIN); - COINS++; - } - } - } - - s = random.nextInt(4); - e = random.nextInt(4); - - // this fills the set of blocks and the hidden objects inside them - if (floor - 4 > 0) { - if ((xLength - 1 - e) - (xStart + 1 + s) > 2) { - for (int x = xStart + 1 + s; x < xLength - 1 - e; x++) { - if (rocks) { - if (x != xStart + 1 && x != xLength - 2 - && random.nextInt(3) == 0) { - if (random.nextInt(4) == 0) { - setBlock(x, floor - 4, BLOCK_POWERUP); - BLOCKS_POWER++; - } else { // the fills a block with a hidden coin - setBlock(x, floor - 4, BLOCK_COIN); - BLOCKS_COINS++; - } - } else if (random.nextInt(4) == 0) { - if (random.nextInt(4) == 0) { - setBlock(x, floor - 4, (byte) (2 + 1 * 16)); - } else { - setBlock(x, floor - 4, (byte) (1 + 1 * 16)); - } - } else { - setBlock(x, floor - 4, BLOCK_EMPTY); - BLOCKS_EMPTY++; - } - } - } - } - } - } + // private void decorate(int xStart, int xLength, int floor) { + // // if its at the very top, just return + // if (floor < 1) + // return; + // + // // boolean coins = random.nextInt(3) == 0; + // boolean rocks = true; + // + // // add an enemy line above the box + // addEnemyLine(xStart + 1, xLength - 1, floor - 1); + // + // int s = random.nextInt(4); + // int e = random.nextInt(4); + // + // if (floor - 2 > 0) { + // if ((xLength - 1 - e) - (xStart + 1 + s) > 1) { + // for (int x = xStart + 1 + s; x < xLength - 1 - e; x++) { + // setBlock(x, floor - 2, COIN); + // COINS++; + // } + // } + // } + // + // s = random.nextInt(4); + // e = random.nextInt(4); + // + // // this fills the set of blocks and the hidden objects inside them + // if (floor - 4 > 0) { + // if ((xLength - 1 - e) - (xStart + 1 + s) > 2) { + // for (int x = xStart + 1 + s; x < xLength - 1 - e; x++) { + // if (rocks) { + // if (x != xStart + 1 && x != xLength - 2 + // && random.nextInt(3) == 0) { + // if (random.nextInt(4) == 0) { + // setBlock(x, floor - 4, BLOCK_POWERUP); + // BLOCKS_POWER++; + // } else { // the fills a block with a hidden coin + // setBlock(x, floor - 4, BLOCK_COIN); + // BLOCKS_COINS++; + // } + // } else if (random.nextInt(4) == 0) { + // if (random.nextInt(4) == 0) { + // setBlock(x, floor - 4, (byte) (2 + 1 * 16)); + // } else { + // setBlock(x, floor - 4, (byte) (1 + 1 * 16)); + // } + // } else { + // setBlock(x, floor - 4, BLOCK_EMPTY); + // BLOCKS_EMPTY++; + // } + // } + // } + // } + // } + // } private void fixWalls() { boolean[][] blockMap = new boolean[width + 1][height + 1];