Initial commit.
This commit is contained in:
563
src/dk/itu/mario/level/CustomizedLevel.java
Normal file
563
src/dk/itu/mario/level/CustomizedLevel.java
Normal file
@@ -0,0 +1,563 @@
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user