package dk.itu.mario.level; import java.util.Random; import dk.itu.mario.MarioInterface.Constraints; import dk.itu.mario.MarioInterface.GamePlay; import dk.itu.mario.MarioInterface.LevelInterface; import dk.itu.mario.engine.sprites.Enemy; import dk.itu.mario.engine.sprites.SpriteTemplate; public class CustomizedLevel extends Level implements LevelInterface { Random random; private static final int ODDS_STRAIGHT = 0; private static final int ODDS_HILL_STRAIGHT = 1; private static final int ODDS_TUBES = 2; private static final int ODDS_JUMP = 3; private static final int ODDS_CANNONS = 4; private static final int JumpingThreshold = 3; private int[] odds = new int[5]; private int totalOdds; private int difficulty; private int type; private int gaps; private int turtles; private int coins; private GamePlay playerM; public CustomizedLevel(int width, int height, long seed, int difficulty, int type, GamePlay playerMetrics) { super(width, height); this.playerM = playerMetrics; creat(seed, difficulty, type); } public void creat(long seed, int difficulty, int type) { this.type = type; this.difficulty = difficulty; odds[ODDS_STRAIGHT] = 30; odds[ODDS_HILL_STRAIGHT] = 20; odds[ODDS_TUBES] = 2 + 2 * difficulty; int jumpDifficulty = 1; // adapt the game so that it has a number of gaps proportional to the // number of jumps the player made in the test level. The more the // jumps, // the more the gaps. if (playerM.jumpsNumber > JumpingThreshold) jumpDifficulty = 2; odds[ODDS_JUMP] = jumpDifficulty; odds[ODDS_CANNONS] = -10 + 5 * difficulty; if (type != LevelInterface.TYPE_OVERGROUND) { odds[ODDS_HILL_STRAIGHT] = 0; } for (int i = 0; i < odds.length; i++) { // failsafe (no negative odds) if (odds[i] < 0) { odds[i] = 0; } totalOdds += odds[i]; odds[i] = totalOdds - odds[i]; } random = new Random(seed); // create the start location int length = 0; length += buildStraight(0, getWidth(), true); // create all of the medium sections while (length < getWidth() - 64) { length += buildZone(length, getWidth() - length); } // set the end piece int floor = height - 1 - random.nextInt(4); // create the exit xExit = length + 8; yExit = floor; for (int x = length; x < getWidth(); x++) { for (int y = 0; y < height; y++) { if (y >= floor) { setBlock(x, y, Level.GROUND); } } } if (type == LevelInterface.TYPE_CASTLE || type == LevelInterface.TYPE_UNDERGROUND) { int ceiling = 0; int run = 0; for (int x = 0; x < width; x++) { if (run-- <= 0 && x > 4) { ceiling = random.nextInt(4); run = random.nextInt(4) + 4; } for (int y = 0; y < height; y++) { if ((x > 4 && y <= ceiling) || x < 1) { setBlock(x, y, GROUND); } } } } fixWalls(); } private int buildZone(int x, int maxLength) { int t = random.nextInt(totalOdds); int type = 0; for (int i = 0; i < odds.length; i++) { if (odds[ODDS_JUMP] <= t * 2 + 30) { type = ODDS_JUMP; break; } if (odds[i] <= t) { type = i; } } switch (type) { case ODDS_STRAIGHT: return buildStraight(x, maxLength, false); case ODDS_HILL_STRAIGHT: return buildHillStraight(x, maxLength); case ODDS_TUBES: return buildTubes(x, maxLength); case ODDS_JUMP: if (gaps < Constraints.gaps) return buildJump(x, maxLength); else return buildStraight(x, maxLength, false); case ODDS_CANNONS: return buildCannons(x, maxLength); } return 0; } private int buildJump(int xo, int maxLength) { gaps++; // jl: jump length // js: the number of blocks that are available at either side for free int js = random.nextInt(4) + 2; int jl = random.nextInt(2) + 2; int length = js * 2 + jl; boolean hasStairs = random.nextInt(3) == 0; int floor = height - 1 - random.nextInt(4); // run for the from the start x position, for the whole length for (int x = xo; x < xo + length; x++) { if (x < xo + js || x > xo + length - js - 1) { // run for all y's since we need to paint blocks upward for (int y = 0; y < height; y++) { // paint ground up until the // floor if (y >= floor) { setBlock(x, y, GROUND); } // if it is above ground, start making stairs of rocks else if (hasStairs) { // LEFT SIDE if (x < xo + js) { // we need to max it out and level // because it wont // paint ground correctly unless two bricks are side // by side if (y >= floor - (x - xo) + 1) { setBlock(x, y, ROCK); } } else { // RIGHT SIDE if (y >= floor - ((xo + length) - x) + 2) { setBlock(x, y, ROCK); } } } } } } return length; } private int buildCannons(int xo, int maxLength) { int length = random.nextInt(10) + 2; if (length > maxLength) length = maxLength; int floor = height - 1 - random.nextInt(4); int xCannon = xo + 1 + random.nextInt(4); for (int x = xo; x < xo + length; x++) { if (x > xCannon) { xCannon += 2 + random.nextInt(4); } if (xCannon == xo + length - 1) xCannon += 10; int cannonHeight = floor - random.nextInt(4) - 1; for (int y = 0; y < height; y++) { if (y >= floor) { setBlock(x, y, (byte) (1 + 9 * 16)); } else { if (x == xCannon && y >= cannonHeight) { if (y == cannonHeight) { setBlock(x, y, (byte) (14 + 0 * 16)); } else if (y == cannonHeight + 1) { setBlock(x, y, (byte) (14 + 1 * 16)); } else { setBlock(x, y, (byte) (14 + 2 * 16)); } } } } } return length; } private int buildHillStraight(int xo, int maxLength) { int length = random.nextInt(10) + 10; if (length > maxLength) length = maxLength; int floor = height - 1 - random.nextInt(4); for (int x = xo; x < xo + length; x++) { for (int y = 0; y < height; y++) { if (y >= floor) { setBlock(x, y, Level.GROUND); } } } addEnemyLine(xo + 1, xo + length - 1, floor - 1); int h = floor; boolean keepGoing = true; boolean[] occupied = new boolean[length]; while (keepGoing) { h = h - 2 - random.nextInt(3); if (h <= 0) { keepGoing = false; } else { int l = random.nextInt(5) + 3; int xxo = random.nextInt(length - l - 2) + xo + 1; if (occupied[xxo - xo] || occupied[xxo - xo + l] || occupied[xxo - xo - 1] || occupied[xxo - xo + l + 1]) { keepGoing = false; } else { occupied[xxo - xo] = true; occupied[xxo - xo + l] = true; addEnemyLine(xxo, xxo + l, h - 1); if (random.nextInt(4) == 0) { decorate(xxo - 1, xxo + l + 1, h); keepGoing = false; } for (int x = xxo; x < xxo + l; x++) { for (int y = h; y < floor; y++) { int xx = 5; if (x == xxo) xx = 4; if (x == xxo + l - 1) xx = 6; int yy = 9; if (y == h) yy = 8; if (getBlock(x, y) == 0) { setBlock(x, y, (byte) (xx + yy * 16)); } else { if (getBlock(x, y) == Level.HILL_TOP_LEFT) setBlock(x, y, Level.HILL_TOP_LEFT_IN); if (getBlock(x, y) == Level.HILL_TOP_RIGHT) setBlock(x, y, Level.HILL_TOP_RIGHT_IN); } } } } } } return length; } private void addEnemyLine(int x0, int x1, int y) { for (int x = x0; x < x1; x++) { if (random.nextInt(50) < 25) { int type = random.nextInt(4); type = random.nextInt(3); if (turtles < Constraints.turtels) { if (type == Enemy.ENEMY_GREEN_KOOPA || type == Enemy.ENEMY_RED_KOOPA) { turtles++; setSpriteTemplate(x, y, new SpriteTemplate(type, random.nextInt(35) < difficulty)); } else { setSpriteTemplate(x, y, new SpriteTemplate(type, random.nextInt(35) < difficulty)); } } else { setSpriteTemplate( x, y, new SpriteTemplate(Enemy.ENEMY_GOOMBA, random .nextInt(35) < difficulty)); } } } } private int buildTubes(int xo, int maxLength) { int length = random.nextInt(10) + 5; if (length > maxLength) length = maxLength; int floor = height - 1 - random.nextInt(4); int xTube = xo + 1 + random.nextInt(4); int tubeHeight = floor - random.nextInt(2) - 2; for (int x = xo; x < xo + length; x++) { if (x > xTube + 1) { xTube += 3 + random.nextInt(4); tubeHeight = floor - random.nextInt(2) - 2; } if (xTube >= xo + length - 2) xTube += 10; if (x == xTube && random.nextInt(11) < difficulty + 1) { setSpriteTemplate(x, tubeHeight, new SpriteTemplate( Enemy.ENEMY_FLOWER, false)); } for (int y = 0; y < height; y++) { if (y >= floor) { setBlock(x, y, (byte) (1 + 9 * 16)); } else { if ((x == xTube || x == xTube + 1) && y >= tubeHeight) { int xPic = 10 + x - xTube; if (y == tubeHeight) { // tube top setBlock(x, y, (byte) (xPic + 0 * 16)); } else { // tube side setBlock(x, y, (byte) (xPic + 1 * 16)); } } } } } return length; } private int buildStraight(int xo, int maxLength, boolean safe) { int length = random.nextInt(10) + 2; if (safe) length = 10 + random.nextInt(5); if (length > maxLength) length = maxLength; int floor = height - 1 - random.nextInt(4); // runs from the specified x position to the length of the segment for (int x = xo; x < xo + length; x++) { for (int y = 0; y < height; y++) { if (y >= floor) { setBlock(x, y, Level.GROUND); } } } 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 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, (byte) (2 + 2 * 16)); } } } s = random.nextInt(4); e = random.nextInt(4); 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(2) == 0) { if (random.nextInt(2) == 0) { setBlock(x, floor - 4, BLOCK_POWERUP); } else { if (coins < Constraints.coinBlocks) { coins++; setBlock(x, floor - 4, BLOCK_COIN); } else { setBlock(x, floor - 4, BLOCK_EMPTY); } } } 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); } } } } } } private void fixWalls() { boolean[][] blockMap = new boolean[width + 1][height + 1]; for (int x = 0; x < width + 1; x++) { for (int y = 0; y < height + 1; y++) { int blocks = 0; for (int xx = x - 1; xx < x + 1; xx++) { for (int yy = y - 1; yy < y + 1; yy++) { if (getBlockCapped(xx, yy) == GROUND) { blocks++; } } } blockMap[x][y] = blocks == 4; } } blockify(this, blockMap, width + 1, height + 1); } private void blockify(Level level, boolean[][] blocks, int width, int height) { int to = 0; if (type == LevelInterface.TYPE_CASTLE) { to = 4 * 2; } else if (type == LevelInterface.TYPE_UNDERGROUND) { to = 4 * 3; } boolean[][] b = new boolean[2][2]; for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { for (int xx = x; xx <= x + 1; xx++) { for (int yy = y; yy <= y + 1; yy++) { int _xx = xx; int _yy = yy; if (_xx < 0) _xx = 0; if (_yy < 0) _yy = 0; if (_xx > width - 1) _xx = width - 1; if (_yy > height - 1) _yy = height - 1; b[xx - x][yy - y] = blocks[_xx][_yy]; } } if (b[0][0] == b[1][0] && b[0][1] == b[1][1]) { if (b[0][0] == b[0][1]) { if (b[0][0]) { level.setBlock(x, y, (byte) (1 + 9 * 16 + to)); } else { // KEEP OLD BLOCK! } } else { if (b[0][0]) { // down grass top? level.setBlock(x, y, (byte) (1 + 10 * 16 + to)); } else { // up grass top level.setBlock(x, y, (byte) (1 + 8 * 16 + to)); } } } else if (b[0][0] == b[0][1] && b[1][0] == b[1][1]) { if (b[0][0]) { // right grass top level.setBlock(x, y, (byte) (2 + 9 * 16 + to)); } else { // left grass top level.setBlock(x, y, (byte) (0 + 9 * 16 + to)); } } else if (b[0][0] == b[1][1] && b[0][1] == b[1][0]) { level.setBlock(x, y, (byte) (1 + 9 * 16 + to)); } else if (b[0][0] == b[1][0]) { if (b[0][0]) { if (b[0][1]) { level.setBlock(x, y, (byte) (3 + 10 * 16 + to)); } else { level.setBlock(x, y, (byte) (3 + 11 * 16 + to)); } } else { if (b[0][1]) { // right up grass top level.setBlock(x, y, (byte) (2 + 8 * 16 + to)); } else { // left up grass top level.setBlock(x, y, (byte) (0 + 8 * 16 + to)); } } } else if (b[0][1] == b[1][1]) { if (b[0][1]) { if (b[0][0]) { // left pocket grass level.setBlock(x, y, (byte) (3 + 9 * 16 + to)); } else { // right pocket grass level.setBlock(x, y, (byte) (3 + 8 * 16 + to)); } } else { if (b[0][0]) { level.setBlock(x, y, (byte) (2 + 10 * 16 + to)); } else { level.setBlock(x, y, (byte) (0 + 10 * 16 + to)); } } } else { level.setBlock(x, y, (byte) (0 + 1 * 16 + to)); } } } } }