Files
n-gon-improved/js/level.procedural.js
2019-07-11 10:04:58 -07:00

999 lines
45 KiB
JavaScript

//global game variables
let body = []; //non static bodies
let map = []; //all static bodies
let cons = []; //all constaints between a point and a body
let consBB = []; //all constaints between two bodies
//main object for spawning levels
const level = {
onLevel: undefined,
start: function() {
// game.levelsCleared = 3; //for testing to simulate all possible mobs spawns
// game.draw.setMapColors();
spawn.setSpawnList(); //picks a couple mobs types for a themed random mob spawns
// this.procedural();
this.testingMap();
//this.warehouse(); //this.highrise(); //this.towers(); // this.skyscrapers(); //this.rooftops();
this.addToWorld(); //add map to world
game.draw.setPaths();
this.levelAnnounce();
},
//******************************************************************************************************************
//******************************************************************************************************************
//empty map for testing mobs
testingMap: function() {
// game.levelsCleared = 5; //for testing to simulate all possible mobs spawns
// for (let i = 0; i < 5; i++) {
// game.dmgScale += 0.4; //damage done by mobs increases each level
// b.dmgScale *= 0.9; //damage done by player decreases each level
// }
mech.setPosToSpawn(-75, -60); //normal spawn
level.enter.x = mech.spawnPos.x - 50;
level.enter.y = mech.spawnPos.y + 20;
level.exit.x = 3500;
level.exit.y = -870;
this.addZone(level.exit.x, level.exit.y, 100, 30, "nextLevel");
// this.addZone(250, -1000, 500, 1500, "laser");
//spawn.debris(0, -900, 4500, 10); //15 debris per level
// setTimeout(function() {
// document.body.style.backgroundColor = "#eee";
// }, 1);
document.body.style.backgroundColor = "#fff";
// document.body.style.backgroundColor = "#fafcff";
// document.body.style.backgroundColor = "#bbb";
// document.body.style.backgroundColor = "#eee4e4";
// document.body.style.backgroundColor = "#dcdcde";
// document.body.style.backgroundColor = "#e0e5e0";
// this.addQueryRegion(550, -25, 100, 50, "bounce", { Vx: 0, Vy: -25 });
// level.fillBG.push({ x: 550, y: -25, width: 100, height: 50, color: "#ff0" });
spawn.mapRect(-1200, 0, 2200, 300); //left ground
spawn.mapRect(3500, -860, 100, 50); //ground bump wall
spawn.mapVertex(1250, 0, "0 0 0 300 -500 600 -500 300");
spawn.mapRect(1500, -300, 2000, 300); //upper ground
spawn.mapVertex(3750, 0, "0 600 0 300 -500 0 -500 300");
spawn.mapRect(4000, 0, 1000, 300); //right lower ground
spawn.mapRect(2200, -600, 600, 50); //center platform
spawn.mapRect(1300, -850, 700, 50); //center platform
spawn.mapRect(3000, -850, 700, 50); //center platform
// spawn.mapRect(0, -2000, 3000, 50); //center platform
spawn.spawnBuilding(-200, -250, 275, 240, false, true, "left"); //far left; player spawns in side
// spawn.boost(350, 0, -1000);
for (let i = 0; i < 17; i++) {
powerUps.spawn(450, -125, "gun", false);
}
for (let i = 0; i < 5; i++) {
powerUps.spawn(2500 + i * 20, -1300, "gun", false);
powerUps.spawn(2500 + i * 20, -1100, "ammo", false);
}
spawn.bodyRect(700, -50, 50, 50);
spawn.bodyRect(700, -100, 50, 50);
spawn.bodyRect(700, -150, 50, 50);
spawn.bodyRect(700, -200, 50, 50);
spawn.bodyRect(-100, -260, 250, 10);
// spawn.springer(100, -550);
// spawn.grower(100, -550);
// spawn.chaser(100, -550);
// spawn.striker(100, -550);
// spawn.spinner(100, -550);
// spawn.hopper(100, -550);
// spawn.grower(100, -550);
// spawn.springer(100, -550);
// spawn.zoomer(100, -550);
// spawn.shooter(100, -550);
// spawn.beamer(100, -550);
// spawn.focuser(100, -550);
// spawn.laser(100, -550);
// spawn.blinker(100, -550);
// spawn.drifter(100, -550);
// spawn.sucker(100, -550);
// spawn.exploder(100, -550);
// spawn.spawner(100, -550);
// spawn.ghoster(100, -550);
// spawn.sneaker(100, -550);
// spawn.bomber(100, -550);
// spawn.flocker(-600, -650);
// spawn.flocker(-600, -550);
// spawn.flocker(-600, -750);
// spawn.starter(-600, -550);
// spawn.flocker(-900, -850);
// spawn.flocker(-600, -550);
// spawn.flocker(-600, -750);
spawn.starter(-600, -550);
// for (let i = 0; i < 4; ++i) {
// spawn.shooter(800, -1150);
// }
// spawn.nodeBoss(900, -1070, "shooter", 9);
// spawn.randomBoss(-100, -1470);
// spawn.randomBoss(500, -1470);
// spawn.randomBoss(900, -1470);
// spawn.randomBoss(900, -1000);
},
//****************************************************************************************************
//****************************************************************************************************
//****************************************************************************************************
//****************************************************************************************************
//****************************************************************************************************
procedural: function() {
const mobChance = 0.3;
const maxJump = 390;
const boostScale = 0.000023;
//
mech.setPosToSpawn(0, -10); //normal spawn
level.enter.x = mech.spawnPos.x - 50;
level.enter.y = mech.spawnPos.y - 15;
//starting zone
spawn.mapRect(-250, -320, 50, 400); //far left starting left wall
spawn.mapRect(-250, -0, 500, 110); //far left starting ground
spawn.mapRect(-250, -340, 500, 50); //far left starting ceiling
spawn.mapRect(200, -320, 50, 180); //far left starting right part of wall
spawn.bodyRect(220, -120, 14, 140, 1, spawn.propsFriction); //door to starting room
spawn.mapRect(-50, -10, 100, 50);
spawn.mapRect(0, 10, 400, 100); //***********ground
if (b.inventory.length < 3) {
powerUps.spawn(550, -50, "gun", false); //starting gun
} else {
powerUps.spawnRandomPowerUp(550, -50);
}
level.fill.push({
x: -250,
y: -300,
width: 500,
height: 300,
color: "rgba(0,0,0,0.15)"
});
let o = { x: 400, y: 10 }; //keeps track of where the next mapNode should be added
mapNode = [
function() {
//one or two shelves
let nodeRange = { x: 650 + Math.round(Math.random() * 900), y: 0 };
spawn.mapRect(o.x, o.y, nodeRange.x, 100);
spawn.randomMob(o.x + 200 + 600 * Math.random(), o.y - 50, mobChance);
spawn.debris(o.x + 50, o.y, nodeRange.x - 100, 2);
//shelf(s)
const shelfElevation = 230 + 200 * Math.random();
const shelfWidth = nodeRange.x - 200 - 300 * Math.random();
if (Math.random() < 0.85 && shelfWidth > 650) {
const len = 1 + Math.ceil(Math.random() * Math.random() * Math.random() * 5);
const sep = 50 + 100 * Math.random();
const x1 = o.x + nodeRange.x / 2 - shelfWidth / 2;
const x2 = o.x + nodeRange.x / 2 + sep;
for (let i = 1; i < len; ++i) {
//two shelves
spawn.mapRect(x1, o.y - shelfElevation * i, shelfWidth / 2 - sep, 50);
spawn.mapRect(x2, o.y - shelfElevation * i, shelfWidth / 2 - sep, 50);
//plank connecting shelves
spawn.bodyRect(
o.x + (nodeRange.x - shelfWidth) / 2 + shelfWidth / 2 - sep - 75,
o.y - shelfElevation * i - 30,
sep + 250,
10,
0.6,
spawn.propsFrictionMedium
);
}
level.fillBG.push({
x: x1,
y: o.y - shelfElevation * (len - 1),
width: shelfWidth / 2 - sep,
height: shelfElevation * (len - 1),
color: "#f0f0f3"
});
level.fillBG.push({
x: x2,
y: o.y - shelfElevation * (len - 1),
width: shelfWidth / 2 - sep,
height: shelfElevation * (len - 1),
color: "#f0f0f3"
});
} else {
const len = 1 + Math.ceil(Math.random() * Math.random() * Math.random() * 5);
for (let i = 1; i < len; ++i) {
//one shelf
spawn.mapRect(o.x + (nodeRange.x - shelfWidth) / 2, o.y - shelfElevation * i, shelfWidth, 50);
level.fillBG.push({
x: o.x + (nodeRange.x - shelfWidth) / 2,
y: o.y - shelfElevation * (len - 1),
width: shelfWidth,
height: shelfElevation * (len - 1),
color: "#f0f0f3"
});
}
}
//square block
const blockSize = 60 + Math.random() * 120;
if (shelfElevation > blockSize + 100) {
spawn.bodyRect(o.x + 100 + Math.random() * (nodeRange.x - 200), o.y - blockSize, blockSize, blockSize, 0.3);
} else {
spawn.bodyRect(o.x + 50 + (nodeRange.x - shelfWidth) / 2, o.y - shelfElevation - blockSize, blockSize, blockSize, 0.3);
}
spawn.randomMob(o.x + (nodeRange.x - shelfWidth) / 2, o.y - shelfElevation - 100, mobChance); //mob above shelf
spawn.debris(o.x + 50 + (nodeRange.x - shelfWidth) / 2, o.y - shelfElevation - 50, shelfWidth - 100, 1);
// set starting position for new mapNode
o.x += nodeRange.x;
o.y += nodeRange.y;
},
function() {
//several platforms that rise up
const wide = 120 + Math.floor(Math.random() * Math.random() * 450);
let nodeRange = { x: 100, y: -Math.floor(200 + Math.random() * 150) };
for (let i = 0, len = 1 + Math.ceil(Math.random() * 4); i < len; i++) {
spawn.platform(o.x + nodeRange.x, o.y, wide, nodeRange.y);
spawn.debris(o.x + nodeRange.x - 120, o.y - 50, wide + 250, Math.floor(Math.random() * 0.8 + 0.5));
if (Math.random() < 0.3) {
spawn.randomBoss(o.x + nodeRange.x + 20 + (wide - 40) * Math.random(), o.y + nodeRange.y - 450, mobChance);
} else {
spawn.randomMob(o.x + nodeRange.x + 20 + (wide - 40) * Math.random(), o.y + nodeRange.y - 50, mobChance); //mob above shelf
}
nodeRange.x += Math.floor(wide + 155 + Math.random() * 200);
nodeRange.y -= Math.floor(115 + Math.random() * 200);
}
spawn.mapRect(o.x, o.y, nodeRange.x, 100); //ground
spawn.mapRect(o.x + nodeRange.x, o.y + nodeRange.y + 15, 100, -nodeRange.y + 85); //right wall
// set starting position for new mapNode
o.x += nodeRange.x;
o.y += nodeRange.y;
},
function() {
//s-shaped building goes up 2 levels
const floorHeight = maxJump - Math.floor(Math.random() * 150); //maxJump = 390
let nodeRange = { x: 700 + Math.floor(Math.random() * 800), y: -floorHeight * 2 };
const wallWidth = 20 + Math.floor(Math.random() * 40);
const numberOfFloors = 2 + Math.floor(Math.random() * 2);
const frontYardWidth = 250;
o.x += frontYardWidth;
spawn.mapRect(o.x - frontYardWidth, o.y, nodeRange.x + frontYardWidth, 100); //first floor ground
let floorWidth = nodeRange.x - wallWidth - 250 - Math.random() * Math.random() * nodeRange.x * 0.4; //possible open area with only half long 2nd floor
spawn.mapRect(o.x + wallWidth, o.y - floorHeight, floorWidth, wallWidth); //second floor
spawn.mapRect(o.x + 300, o.y - floorHeight * 2, nodeRange.x - 300, wallWidth); //third floor
if (numberOfFloors > 2) spawn.mapRect(o.x, o.y - floorHeight * 3, nodeRange.x, wallWidth); //optional roof
spawn.mapRect(o.x, o.y - floorHeight * numberOfFloors, wallWidth, floorHeight * numberOfFloors - 175); //left building wall
if (Math.random() < 0.8) {
spawn.mapRect(o.x + nodeRange.x - wallWidth, o.y - floorHeight * 2 + wallWidth, wallWidth, floorHeight * 2); //right building wall
} else {
spawn.mapRect(o.x + nodeRange.x - wallWidth, o.y - floorHeight * 2 + wallWidth, wallWidth, floorHeight * 2 - 175 - wallWidth); //right building wall with right door
}
level.fill.push({
x: o.x,
y: o.y - floorHeight * numberOfFloors,
width: nodeRange.x,
height: floorHeight * numberOfFloors,
color: "rgba(0,0,0,0.1)"
});
//random extras
const debrisRange = nodeRange.x - wallWidth * 4;
spawn.debris(o.x + wallWidth, o.y - 50, debrisRange, 1);
spawn.debris(o.x + wallWidth, o.y - 50 - floorHeight, debrisRange - 250, 1);
spawn.debris(o.x + wallWidth + 250, o.y - 50 - floorHeight * 2, debrisRange - 250, 1);
spawn.randomSmallMob(o.x + wallWidth + Math.random() * debrisRange, o.y - 80, 3);
spawn.randomSmallMob(o.x + wallWidth + Math.random() * (debrisRange - 250), o.y - 80 - floorHeight);
spawn.randomSmallMob(o.x + wallWidth + 250 + Math.random() * (debrisRange - 250), o.y - 80 - floorHeight * 2);
let blockSize = 70 + Math.random() * 70;
spawn.bodyRect(o.x - blockSize + nodeRange.x - wallWidth - Math.random() * 30, o.y - blockSize, blockSize, blockSize, 0.4);
blockSize = 70 + Math.random() * 100;
spawn.bodyRect(o.x + wallWidth + Math.random() * 30, o.y - floorHeight - blockSize, blockSize, blockSize, 0.4);
o.x += nodeRange.x;
if (Math.random() < 0.5) o.y += nodeRange.y; //start the next level at the top floor of the building
},
function() {
//building with several floors that goes down a couple levels
const numberOfFloors = 2 + Math.floor(Math.random() * 2);
const floorHeight = maxJump - Math.floor(Math.random() * 150); //maxJump = 390
let nodeRange = { x: 825 + Math.floor(Math.random() * 800), y: floorHeight * numberOfFloors };
const wallWidth = 20 + Math.floor(Math.random() * 40);
const frontYardWidth = 250;
o.x += frontYardWidth;
spawn.mapRect(o.x, o.y - floorHeight * 2, nodeRange.x, wallWidth); //roof level 2
if (Math.random() < 0.5) {
spawn.mapRect(o.x + 300, o.y - floorHeight, nodeRange.x - 600, wallWidth); //level 1
} else if (Math.random() < 0.5) {
spawn.mapRect(o.x + 300, o.y - floorHeight, nodeRange.x - 600, wallWidth + floorHeight); //level 1
}
spawn.mapRect(o.x - frontYardWidth, o.y, nodeRange.x + frontYardWidth - 300, wallWidth); //ground
// spawn.mapRect(o.x - frontYardWidth, o.y + 10, frontYardWidth, 100 - 10); // makes the front yard look 100 deep
let floorWidth = nodeRange.x - wallWidth - 250 - Math.random() * Math.random() * nodeRange.x * 0.4; //possible open area with only half long 2nd floor
spawn.mapRect(o.x + nodeRange.x - floorWidth, o.y + floorHeight, floorWidth, wallWidth); //B1 floor
spawn.mapRect(o.x, o.y + floorHeight * numberOfFloors, nodeRange.x, 100); //B2 floor
spawn.mapRect(o.x, o.y - floorHeight * 2, wallWidth, floorHeight * 2 - 175); //left building wall above ground
spawn.mapRect(o.x, o.y + wallWidth, wallWidth, floorHeight * numberOfFloors); //left building wall lower
spawn.mapRect(o.x + nodeRange.x - wallWidth, o.y + wallWidth - floorHeight * 2, wallWidth, floorHeight * (numberOfFloors + 2) - wallWidth - 175); //right building wall with right door
level.fill.push({
x: o.x,
y: o.y - floorHeight * 2,
width: nodeRange.x,
height: floorHeight * (numberOfFloors + 2),
color: "rgba(0,0,0,0.1)"
});
//random extras
spawn.debris(o.x, o.y - 50, nodeRange.x - 300, 1); //ground
spawn.debris(o.x, o.y + floorHeight * 2 - 50, nodeRange.x, 1); //B2
spawn.randomSmallMob(o.x + wallWidth + Math.random() * nodeRange.x - 300, o.y - 50); //ground
if (numberOfFloors === 3) {
spawn.randomBoss(o.x + nodeRange.x / 2, o.y + floorHeight * 2 - 50);
} else {
spawn.randomSmallMob(o.x + wallWidth + Math.random() * nodeRange.x * 0.8, o.y + floorHeight - 50); //B1
spawn.randomSmallMob(o.x + wallWidth + Math.random() * nodeRange.x * 0.8, o.y + floorHeight * numberOfFloors - 50); //B2
}
o.x += nodeRange.x;
o.y += nodeRange.y; //start the next level at the top floor of the building
},
function() {
//large room with boost to roof exit
const wallWidth = 20 + Math.floor(Math.random() * 40);
const boostX = 500 + Math.floor(Math.random() * 1500);
const boostPadding = 35 + Math.floor(Math.random() * 200);
let nodeRange = { x: boostX + 500 + Math.floor(Math.random() * 500), y: 700 + Math.floor(Math.random() * 600) };
//optional basement mode
if (Math.random() < 0.75 && boostX > 1000) {
spawn.mapRect(o.x, o.y, 200 + wallWidth, wallWidth); //ground entrance
const basementDepth = Math.min(400 + Math.floor(Math.random() * 300), nodeRange.y - 200);
o.y += basementDepth;
o.x += 200;
spawn.mapRect(o.x, o.y, nodeRange.x, 100); //basement ground
spawn.mapRect(o.x, o.y - nodeRange.y + 15, wallWidth, nodeRange.y - 200 - basementDepth); //left building wall
spawn.mapRect(o.x, o.y - basementDepth + 15, wallWidth, basementDepth); //left basement wall
} else {
spawn.mapRect(o.x, o.y, nodeRange.x + 200, 100); //ground
o.x += 200;
spawn.mapRect(o.x, o.y - nodeRange.y + 15, wallWidth, nodeRange.y - 200); //left building wall
}
spawn.mapRect(o.x + nodeRange.x - wallWidth, o.y - nodeRange.y + 15, wallWidth, nodeRange.y); //right building wall
spawn.mapRect(o.x, o.y - nodeRange.y, boostX - boostPadding, wallWidth); //left roof
spawn.mapRect(o.x + boostX + 100 + boostPadding, o.y - nodeRange.y, nodeRange.x - boostX - 100 - boostPadding, wallWidth); //right roof
if (boostPadding < 100 && nodeRange.y < 1300) {
spawn.boost(o.x + boostX, o.y, nodeRange.y + 600);
spawn.bodyRect(o.x + boostX - boostPadding - 100, o.y - nodeRange.y - 20, 300 + 2 * boostPadding, 10, 1);
} else {
spawn.boost(o.x + boostX, o.y, nodeRange.y);
}
spawn.debris(o.x, o.y - nodeRange.y - 50, boostX - boostPadding, 1); //on roof
spawn.debris(o.x, o.y - 50, boostX - boostPadding, 1); //on ground
let blockSize = 60 + Math.random() * 150;
spawn.bodyRect(o.x + wallWidth + Math.random() * (boostX - blockSize - wallWidth), o.y - blockSize, blockSize, blockSize, 0.8); //left
spawn.bodyRect(o.x + nodeRange.x - blockSize - 10, o.y - blockSize, blockSize, blockSize, 0.8); //right
const ledgeHeight = 500 + Math.random() * (nodeRange.y - 900) - 150;
if (Math.random() < 0.5) {
spawn.randomMob(o.x + 200, o.y - ledgeHeight, mobChance); //mob in left top corner
spawn.randomBoss(o.x + boostX + 100 + boostPadding + 100, o.y - nodeRange.y - 500, mobChance); //boss above right roof
} else {
spawn.randomBoss(o.x + 300, o.y - ledgeHeight); //mob in left top corner
spawn.randomMob(o.x + boostX + 100 + boostPadding + 100, o.y - ledgeHeight, mobChance); //mob above right ledge
}
level.fill.push({
x: o.x,
y: o.y - nodeRange.y,
width: nodeRange.x,
height: nodeRange.y,
color: "rgba(0,0,0,0.1)"
});
o.x += nodeRange.x;
if (Math.random() < 0.5) o.y -= nodeRange.y; //start the next level at the top floor of the building or not
},
function() {
//series of platforming ledges
//first platform to get up to top height
let wallWidth = 25 + Math.floor(Math.random() * 30);
const startingX = o.x;
const frontYard = 200;
let firstPlatW = 800 + Math.floor(Math.random() * 350);
o.x += frontYard;
//optional extra lower floor
let zeroFloor = 0;
if (Math.random() < 0.7) {
zeroFloor = maxJump - 100;
spawn.mapRect(o.x, o.y - zeroFloor, firstPlatW + 100, zeroFloor + 15); //0th floor
}
const firstFloorH = maxJump - Math.floor(Math.random() * 50) + zeroFloor;
const fullHeight = firstFloorH + 300 + 300;
const totalCases = 4;
switch (Math.ceil(Math.random() * totalCases)) {
case 1:
spawn.mapRect(o.x, o.y - firstFloorH, firstPlatW, 100); //1st floor
spawn.mapRect(o.x, o.y - firstFloorH - 300, 100, 315); //1st floor left wall
spawn.mapRect(o.x + 300, o.y - fullHeight, firstPlatW - 400, 450); //2st floor
level.fill.push({
//darkness under first floor left building
x: o.x,
y: o.y - firstFloorH,
width: firstPlatW,
height: firstFloorH - zeroFloor,
color: "rgba(0,0,0,0.15)"
});
level.fill.push({
//darkness under second floor left building
x: o.x + 300,
y: o.y - firstFloorH - 300,
width: firstPlatW - 400,
height: firstFloorH - zeroFloor,
color: "rgba(0,0,0,0.2)"
});
break;
case 2:
if (Math.random() < 0.1) {
spawn.mapRect(o.x + 200, o.y - firstFloorH, 200, firstFloorH + 15 - zeroFloor);
} else {
const size = 50 + Math.floor(Math.random() * 100);
for (let i = 0, len = Math.ceil(Math.random() * 8); i < len; ++i) {
spawn.bodyRect(o.x + 200, o.y - zeroFloor - size * (1 + i), size, size);
}
}
spawn.boost(o.x + firstPlatW - 100, o.y - zeroFloor, fullHeight); //-0.007
break;
case 3:
spawn.mapRect(o.x + 200, o.y - firstFloorH, firstPlatW - 200, 100); //1st floor
spawn.mapRect(o.x + 400, o.y - firstFloorH - 300, firstPlatW - 400, 315); //1st floor left wall
spawn.mapRect(o.x + 600, o.y - fullHeight, firstPlatW - 600, 450); //2st floor
level.fill.push({
//darkness under second floor left building
x: o.x + 200,
y: o.y - firstFloorH,
width: firstPlatW - 200,
height: firstFloorH - zeroFloor,
color: "rgba(0,0,0,0.1)"
});
break;
case 4:
const poleWidth = 50;
const platWidth = 200;
const secondPlatX = platWidth + 125;
const totalWidth = platWidth + secondPlatX;
spawn.mapRect(o.x + firstPlatW - totalWidth, o.y - firstFloorH - 350, platWidth, wallWidth);
spawn.mapRect(o.x + firstPlatW - totalWidth, o.y - firstFloorH + 100, platWidth, wallWidth);
spawn.mapRect(o.x + secondPlatX + firstPlatW - totalWidth, o.y - firstFloorH - 100, platWidth, wallWidth);
spawn.mapRect(o.x + secondPlatX + firstPlatW - totalWidth, o.y - fullHeight, platWidth, wallWidth);
level.fillBG.push({
x: o.x + platWidth / 2 - poleWidth / 2 + firstPlatW - totalWidth,
y: o.y - firstFloorH - 350,
width: poleWidth,
height: firstFloorH + 350 - zeroFloor,
color: "rgba(0,0,0,0.2)"
});
level.fillBG.push({
x: o.x + platWidth / 2 - poleWidth / 2 + secondPlatX + firstPlatW - totalWidth,
y: o.y - fullHeight,
width: poleWidth,
height: fullHeight - zeroFloor,
color: "rgba(0,0,0,0.2)"
});
if (Math.random() < 0.9) {
const platX = firstPlatW - totalWidth - platWidth - 125;
spawn.mapRect(o.x + platX, o.y - firstFloorH - 100, platWidth, wallWidth);
spawn.mapRect(o.x + platX, o.y - fullHeight, platWidth, wallWidth);
level.fillBG.push({
x: o.x + platWidth / 2 - poleWidth / 2 + platX,
y: o.y - fullHeight,
width: poleWidth,
height: fullHeight - zeroFloor,
color: "rgba(0,0,0,0.2)"
});
}
break;
}
spawn.debris(o.x, o.y - zeroFloor - 50, firstPlatW, 2);
spawn.randomMob(o.x + firstPlatW - 200 - Math.random() * 600, o.y - zeroFloor - 100, mobChance); //in shadow
spawn.randomMob(o.x + firstPlatW - 200 - Math.random() * 400, o.y - fullHeight - 100, mobChance); //top
spawn.randomBoss(o.x + firstPlatW - 200, o.y - fullHeight - 500, mobChance); //top
//random platforms
let offX = o.x + firstPlatW;
const len = Math.ceil(Math.random() * Math.random() * 4.5);
for (let i = 0; i < len; i++) {
const totalCases = 3;
switch (Math.ceil(Math.random() * totalCases)) {
case 1:
const width = 150 + Math.floor(Math.random() * 500);
const middle = Math.floor(width / 2);
spawn.mapRect(offX + 300, o.y - fullHeight, width, wallWidth); //top platform
if (Math.random() < 0.5) spawn.mapRect(offX + 300, o.y - 50, width, 65); //ground bump
//optional room on second floor
if (width > 400) {
roomHeight = Math.min(maxJump, width) - 100;
roomLipWidth = 200;
spawn.mapRect(offX + 300 + width - wallWidth, o.y - fullHeight - roomHeight, wallWidth, roomHeight + 15); //room right wall
spawn.mapRect(offX + 300 + roomLipWidth, o.y - fullHeight - roomHeight, width - roomLipWidth, wallWidth); //room roof
level.fill.push({
x: offX + 300 + roomLipWidth,
y: o.y - fullHeight - roomHeight + wallWidth,
width: width - roomLipWidth,
height: roomHeight - wallWidth,
color: "rgba(0,0,0,0.1)"
});
} else if (Math.random() < 0.5) {
spawn.mapRect(offX + 300, o.y - firstFloorH, width, wallWidth); //middle platform
spawn.bodyRect(offX + 300 - Math.floor(Math.random() * 100), o.y - fullHeight - 20, width + Math.floor(Math.random() * 300), 20, 0.7); //plank on top platform)
}
level.fillBG.push({
x: offX + 300 + middle - 25,
y: o.y - fullHeight,
width: 50,
height: fullHeight,
color: "rgba(0,0,0,0.2)"
});
spawn.debris(offX + 300, o.y - 50, width, 1);
spawn.randomMob(offX + 300 + Math.random() * width, o.y - fullHeight - 100, 1); //top
offX += 300 + width;
break;
case 2:
const width2 = 500 + Math.floor(Math.random() * 400);
const forkDepth = 300;
const forkBaseHeight = fullHeight - forkDepth - (maxJump - 100) - 250;
spawn.mapRect(offX + 300, o.y - maxJump + 100, width2, maxJump - 100); //base
spawn.mapRect(offX + 300, o.y - fullHeight + forkDepth, width2, forkBaseHeight); //fork base
if (Math.random() < 0.7) spawn.mapRect(offX + 300, o.y - fullHeight, 100, forkDepth); //left fork
spawn.mapRect(offX + 300 + width2 - 100, o.y - fullHeight, 100, forkDepth); //right fork
level.fill.push({
x: offX + 300,
y: o.y - fullHeight + forkDepth + forkBaseHeight,
width: width2,
height: fullHeight - forkDepth - forkBaseHeight - maxJump + 100,
color: "rgba(0,0,0,0.1)"
});
spawn.debris(offX + 300, o.y - maxJump - 100, width2, 1);
spawn.randomMob(offX + 450 + Math.random() * (width2 - 300), o.y - fullHeight + 200, 1); //top
offX += 300 + width2;
break;
case 3:
const width3 = 200 + Math.floor(Math.random() * 300);
if (Math.random() < 0.7) {
spawn.mapRect(offX + 300, o.y - fullHeight, width3, fullHeight - 150); //top platform
level.fill.push({
x: offX + 300,
y: o.y - 150,
width: width3,
height: 150,
color: "rgba(0,0,0,0.25)"
});
} else {
//add a gap
const gap = (fullHeight - 150) / 2 + 100;
spawn.mapRect(offX + 300, o.y - fullHeight, width3, fullHeight - 150 - gap); //top platform
spawn.mapRect(offX + 300, o.y - fullHeight + gap, width3, fullHeight - 150 - gap); //top platform
level.fill.push({
x: offX + 300,
y: o.y - 150,
width: width3,
height: 150,
color: "rgba(0,0,0,0.25)"
});
level.fill.push({
x: offX + 300,
y: o.y - 150 - gap,
width: width3,
height: 200,
color: "rgba(0,0,0,0.25)"
});
}
spawn.randomMob(offX + 300 + Math.random() * width3, o.y - fullHeight - 100, mobChance); //top
spawn.debris(offX + 300, o.y - fullHeight - 100, width3, 1);
offX += 300 + width3;
break;
}
}
o.x += offX - o.x + 200;
spawn.mapRect(startingX, o.y, o.x - startingX + 15, 100); //ground
spawn.mapRect(o.x, o.y - fullHeight + 15, 100, fullHeight + 85); //right wall
o.y -= fullHeight;
},
function() {
const width = 200 + Math.ceil(Math.random() * 200);
const height = (maxJump - 50) * (1 - Math.random() * 0.4);
const len = 2 + Math.ceil(Math.random() * 4);
const gapWidth = 150 + Math.ceil(Math.random() * 325);
const stairsUp = function() {
const x = o.x;
for (let i = 0; i < len; ++i) {
if (Math.random() < 0.4 && height > 200 && i !== 0) {
//hidden alcove
spawn.mapRect(o.x, o.y, width, 50); //ledge
spawn.mapRect(o.x + width - 50, o.y, (len - i - 1) * width + 50, height + 15); //back wall
level.fill.push({
x: o.x,
y: o.y + 50,
width: width - 50,
height: height - 50,
color: "rgba(0,0,0,0.15)"
});
spawn.randomMob(o.x + width - 100, o.y + height / 2 + 50);
} else {
spawn.mapRect(o.x, o.y, (len - i) * width, height + 15); //ledge
}
if (Math.random() < 0.5) spawn.debris(o.x, o.y - 50, width, 1);
o.x += width;
o.y -= height;
}
o.y += height;
};
const stairsDown = function() {
const x = o.x;
for (let i = 0; i < len; ++i) {
if (Math.random() < 0.4 && height > 200 && i !== len - 1) {
//hidden alcove
spawn.mapRect(o.x, o.y, width, 50); //ledge
spawn.mapRect(x, o.y, -x + o.x + 50, height + 15); //back wall
level.fill.push({
x: o.x + 50,
y: o.y + 50,
width: width - 50,
height: height - 50,
color: "rgba(0,0,0,0.15)"
});
spawn.randomSmallMob(o.x + 100, o.y + height / 2 + 50);
} else {
spawn.mapRect(x, o.y, width - x + o.x, height + 15); //ledge
}
if (Math.random() < 0.5) spawn.debris(o.x, o.y - 50, width, 1);
o.x += width;
o.y += height;
}
o.y -= height;
};
const spawnGapBoss = function() {
if (game.levelsCleared !== 0 || Math.random() < 0.3 + game.levelsCleared * 0.11) {
spawn.bodyRect(o.x - 50, o.y - 15, gapWidth + 100, 15); //plank over gap to catch boss
spawn.randomBoss(o.x + gapWidth / 2 - 50, o.y - 500);
} else if (game.levelsCleared < 1) {
spawn.bodyRect(o.x - 50, o.y - 15, gapWidth + 100, 15); //plank over gap
}
};
if (Math.random() < 0.1) {
spawn.mapRect(o.x, o.y, len * width + 300, 100); //front porch
o.x += 300;
spawn.mapRect(o.x + len * width + gapWidth, o.y, len * width + 300, 100); //back porch
o.y -= height;
stairsUp();
spawnGapBoss();
o.x += gapWidth;
stairsDown();
o.y += height;
o.x += 300;
} else {
spawn.mapRect(o.x, o.y, 300, 100); //front porch
o.x += 275;
stairsDown();
spawnGapBoss();
o.x += gapWidth;
stairsUp();
}
o.x -= 15;
}
// function() {
// platform = function(x, y, width, height, extend = 0) {
// spawn.mapRect(x, y - height, width, 50);
// level.fillBG.push({
// x: x + width / 2 - 25,
// y: y - height,
// width: 50,
// height: height + extend,
// color: "rgba(0,0,0,0.15)"
// });
// spawn.debris(x, y - height - 50, width, Math.floor(Math.random() * 1.5));
// spawn.randomMob(x + Math.random() * (width - 50) + 25, y - height - 50, mobChance);
// };
// let nodeRange = { x: 1500 + Math.floor(Math.random() * 500), y: 0, down: false, up: false };
// // const wallWidth = 20 + Math.floor(Math.random() * 40);
// //level 1
// const ledge = { width: nodeRange.x / 2, height: Math.max((maxJump - 200) * Math.random() + 200, 200) };
// if (Math.random() < 0.33) {
// //flat ground
// spawn.mapRect(o.x, o.y, nodeRange.x, 100); //ground
// ledge.height = 0;
// } else {
// if (Math.random() < 0.5) {
// //level down
// nodeRange.down = true;
// spawn.mapRect(o.x, o.y, ledge.width + 100 - 25, 100); //ground
// spawn.mapRect(o.x + ledge.width, o.y, 100, ledge.height + 100); //ledge wall
// o.y += ledge.height;
// spawn.mapRect(o.x + ledge.width, o.y, nodeRange.x - ledge.width, 100); //ground
// const wide = Math.min(250 + Math.random() * (ledge.width - 250), nodeRange.x - ledge.width - 350);
// platform(o.x + 250 + ledge.width, o.y, wide, ledge.height);
// } else {
// //level up
// nodeRange.down = false;
// spawn.mapRect(o.x, o.y, ledge.width + 100, 100); //ground
// spawn.mapRect(o.x + ledge.width, o.y - ledge.height, 100, ledge.height + 100); //ledge wall
// const wide = Math.min(250 + Math.random() * (ledge.width - 250), ledge.width - 250);
// platform(o.x + 150, o.y, wide, ledge.height);
// o.y -= ledge.height;
// spawn.mapRect(o.x + ledge.width + 25, o.y, nodeRange.x - ledge.width - 25, 100); //ground
// }
// }
// // platform(x, o.y, width, maxJump * 2 - 100);
// o.x += nodeRange.x;
// }
// function() {
// platform = function(x, y, width, height) {
// spawn.mapRect(x, y - height, width, 50);
// level.fillBG.push({
// x: x + width / 2 - 25,
// y: y - height,
// width: 50,
// height: height,
// color: "rgba(0,0,0,0.15)"
// });
// spawn.debris(x, y - height - 50, width, Math.floor(Math.random() * 1.5));
// spawn.randomMob(x + Math.random() * (width - 50) + 25, y - height - 50, mobChance);
// };
// let nodeRange = { x: 1500 + Math.floor(Math.random() * 500), y: 0, down: false, up: false };
// let level = maxJump - 100 * Math.random();
// // platform(x, o.y, width, maxJump * 2 - 100);
// o.x += nodeRange.x;
// }
];
//
//
//randomized zone spawns
const mapNodes = Math.min(4, 2 + game.levelsCleared);
// const mapNodes = 1;
for (let i = 0; i < mapNodes; ++i) {
// mapNode[1]();
mapNode[Math.floor(Math.random() * mapNode.length)](); //run a random mapNode
}
//ending zone
o.x += 200;
level.exit.x = o.x + 200;
level.exit.y = o.y - 35;
this.addZone(level.exit.x, level.exit.y, 100, 30, "nextLevel");
spawn.mapRect(o.x + 200, o.y - 20, 100, 50);
spawn.mapRect(o.x + 450, o.y - 330, 50, 380);
spawn.mapRect(o.x - 200, o.y - 10, 700, 110);
spawn.mapRect(o.x, o.y - 325, 50, 100);
spawn.mapRect(o.x, o.y - 350, 500, 50);
// spawn.mapRect(o.x - 200, o.y, 300, 200);
// spawn.mapGunPowerUp(o.x - 50, o.y + 0); //spawns a gun on most early levels
// level.fillBG.push({
// x: o.x,
// y: o.y,
// width: 450,
// height: -350,
// color: "#dff"
// });
level.fill.push({
x: o.x,
y: o.y,
width: 450,
height: -350,
color: "rgba(0, 255, 255, 0.15)"
});
//set new fall height
game.fallHeight = o.y + 15000;
},
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
//*****************************************************************************************************************
enter: {
x: 0,
y: 0,
draw: function() {
ctx.beginPath();
ctx.moveTo(this.x, this.y + 30);
ctx.lineTo(this.x, this.y - 80);
ctx.bezierCurveTo(this.x, this.y - 170, this.x + 100, this.y - 170, this.x + 100, this.y - 80);
ctx.lineTo(this.x + 100, this.y + 30);
ctx.lineTo(this.x, this.y + 30);
ctx.fillStyle = "#ccc";
ctx.fill();
}
},
exit: {
x: 0,
y: 0,
draw: function() {
ctx.beginPath();
ctx.moveTo(this.x, this.y + 30);
ctx.lineTo(this.x, this.y - 80);
ctx.bezierCurveTo(this.x, this.y - 170, this.x + 100, this.y - 170, this.x + 100, this.y - 80);
ctx.lineTo(this.x + 100, this.y + 30);
ctx.lineTo(this.x, this.y + 30);
ctx.fillStyle = "#0ff";
ctx.fill();
}
},
fillBG: [],
drawFillBGs: function() {
for (let i = 0, len = level.fillBG.length; i < len; ++i) {
const f = level.fillBG[i];
ctx.fillStyle = f.color;
ctx.fillRect(f.x, f.y, f.width, f.height);
}
},
fill: [],
drawFills: function() {
for (let i = 0, len = level.fill.length; i < len; ++i) {
const f = level.fill[i];
ctx.fillStyle = f.color;
ctx.fillRect(f.x, f.y, f.width, f.height);
}
},
zones: [], //zone do actions when player is in a region // to effect everything use a query
checkZones: function() {
for (let i = 0, len = this.zones.length; i < len; ++i) {
if (
player.position.x > this.zones[i].x1 &&
player.position.x < this.zones[i].x2 &&
player.position.y > this.zones[i].y1 &&
player.position.y < this.zones[i].y2
) {
this.zoneActions[this.zones[i].action](i);
break;
}
}
},
addZone: function(x, y, width, height, action, info) {
this.zones[this.zones.length] = {
x1: x,
y1: y - 150,
x2: x + width,
y2: y + height - 70, //-70 to adjust for player height
action: action,
info: info
};
},
zoneActions: {
fling: function(i) {
Matter.Body.setVelocity(player, {
x: level.zones[i].info.Vx,
y: level.zones[i].info.Vy
});
},
nextLevel: function() {
//enter when player isn't falling
if (player.velocity.y < 0.1) {
game.dmgScale += 0.3; //damage done by mobs increases each level
b.dmgScale *= 0.92; //damage done by player decreases each level
game.levelsCleared++;
game.clearNow = true; //triggers in the physics engine to remove all physics bodies
}
},
death: function() {
mech.death();
},
laser: function(i) {
//draw these in game with spawn.background
mech.damage(level.zones[i].info.dmg);
},
slow: function() {
Matter.Body.setVelocity(player, {
x: player.velocity.x * 0.5,
y: player.velocity.y * 0.5
});
}
},
queryList: [], //queries do actions on many objects in regions (for only player use a zone)
checkQuery: function() {
let bounds, action, info;
function isInZone(targetArray) {
let results = Matter.Query.region(targetArray, bounds);
for (let i = 0, len = results.length; i < len; ++i) {
level.queryActions[action](results[i], info);
}
}
for (let i = 0, len = level.queryList.length; i < len; ++i) {
bounds = level.queryList[i].bounds;
action = level.queryList[i].action;
info = level.queryList[i].info;
for (let j = 0, l = level.queryList[i].groups.length; j < l; ++j) {
isInZone(level.queryList[i].groups[j]);
}
}
},
//oddly query regions can't get smaller than 50 width?
addQueryRegion: function(x, y, width, height, action, groups = [[player], body, mob, powerUp, bullet], info) {
this.queryList[this.queryList.length] = {
bounds: {
min: {
x: x,
y: y
},
max: {
x: x + width,
y: y + height
}
},
action: action,
groups: groups,
info: info
};
},
queryActions: {
bounce: function(target, info) {
//jerky fling upwards
Matter.Body.setVelocity(target, {
x: info.Vx + (Math.random() - 0.5) * 6,
y: info.Vy
});
target.torque = (Math.random() - 0.5) * 2 * target.mass;
},
boost: function(target, info) {
if (target.velocity.y < 0) {
mech.buttonCD_jump = 0; //reset short jump counter to pre vent short jumps on boosts
Matter.Body.setVelocity(target, {
x: target.velocity.x,
y: info
});
}
},
force: function(target, info) {
if (target.velocity.y < 0) {
//gently force up if already on the way up
target.force.x += info.Vx * target.mass;
target.force.y += info.Vy * target.mass;
} else {
target.force.y -= 0.0007 * target.mass; //gently fall in on the way down
}
},
antiGrav: function(target) {
target.force.y -= 0.0011 * target.mass;
},
death: function(target) {
target.death();
}
},
levelAnnounce: function() {
// let text = "n-gon L" + (game.levelsCleared + 1) + " " + level.levels[level.onLevel];
let text = "n-gon Level " + (game.levelsCleared + 1);
document.title = text;
// text = "Level " + (game.levelsCleared + 1) + ": " + spawn.pickList[0] + "s + " + spawn.pickList[1] + "s";
// game.makeTextLog(text, 300);
// text = text + " with population: ";
// for (let i = 0, len = spawn.pickList.length; i < len; ++i) {
// if (spawn.pickList[i] != spawn.pickList[i - 1]) {
// text += spawn.pickList[i] + ", ";
// }
// }
// this.speech(text);
// game.makeTextLog(text, 360);
},
addToWorld: function(mapName) {
//needs to be run to put bodies into the world
for (let i = 0; i < body.length; i++) {
//body[i].collisionFilter.group = 0;
body[i].collisionFilter.category = 0x0000001;
body[i].collisionFilter.mask = 0x011111;
body[i].classType = "body";
World.add(engine.world, body[i]); //add to world
}
for (let i = 0; i < map.length; i++) {
//map[i].collisionFilter.group = 0;
map[i].collisionFilter.category = 0x000001;
map[i].collisionFilter.mask = 0x111111;
Matter.Body.setStatic(map[i], true); //make static
World.add(engine.world, map[i]); //add to world
}
for (let i = 0; i < cons.length; i++) {
World.add(engine.world, cons[i]);
}
for (let i = 0; i < consBB.length; i++) {
World.add(engine.world, consBB[i]);
}
}
};