diff --git a/js/bullet.js b/js/bullet.js index 94143ba..d1544a2 100644 --- a/js/bullet.js +++ b/js/bullet.js @@ -156,7 +156,7 @@ const b = { } } }, - explosion(where, radius, isBurn = false) { + explosion(where, radius) { radius *= mod.explosionRadius // typically explode is used for some bullets with .onEnd //add dmg to draw queue @@ -969,7 +969,7 @@ const b = { nailBot(position = mech.pos) { const me = bullet.length; const dir = mech.angle; - const RADIUS = (10 + 5 * Math.random()) + const RADIUS = (12 + 4 * Math.random()) bullet[me] = Bodies.polygon(position.x, position.y, 4, RADIUS, { angle: dir, friction: 0, @@ -1076,6 +1076,273 @@ const b = { }) World.add(engine.world, bullet[me]); //add bullet to world }, + plasmaBot(position = mech.pos) { + const me = bullet.length; + const dir = mech.angle; + const RADIUS = 18 + bullet[me] = Bodies.polygon(position.x, position.y, 5, RADIUS, { + angle: dir, + friction: 0, + frictionStatic: 0, + frictionAir: 0.05, + restitution: 1, + dmg: 0, // 0.14 //damage done in addition to the damage from momentum + minDmgSpeed: 2, + lookFrequency: 15, + cd: 0, + acceleration: 0.0085, + endCycle: Infinity, + classType: "bullet", + collisionFilter: { + category: cat.bullet, + mask: cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet | cat.mobShield + }, + lockedOn: null, + onDmg() { + this.lockedOn = null + }, + onEnd() {}, + do() { + const distanceToPlayer = Vector.magnitude(Vector.sub(this.position, mech.pos)) + if (distanceToPlayer > 100) { //if far away move towards player + this.force = Vector.mult(Vector.normalise(Vector.sub(mech.pos, this.position)), this.mass * this.acceleration) + } + Matter.Body.setVelocity(this, Vector.add(Vector.mult(this.velocity, 0.90), Vector.mult(player.velocity, 0.17))); //add player's velocity + + //find closest + if (!(game.cycle % this.lookFrequency)) { + this.lockedOn = null; + let closeDist = mod.isPlasmaRange * 1000; + for (let i = 0, len = mob.length; i < len; ++i) { + const DIST = Vector.magnitude(Vector.sub(this.position, mob[i].position)) - mob[i].radius; + if (DIST < closeDist && mob[i].dropPowerUp && + Matter.Query.ray(map, this.position, mob[i].position).length === 0 && + Matter.Query.ray(body, this.position, mob[i].position).length === 0) { + closeDist = DIST; + this.lockedOn = mob[i] + } + } + } + + //fire plasma at target + + const DRAIN = 0.0014 + if (this.lockedOn && this.lockedOn.alive && mech.energy > DRAIN && mech.fieldCDcycle < mech.cycle) { + mech.energy -= DRAIN; + if (mech.energy < 0) { + mech.fieldCDcycle = mech.cycle + 120; + mech.energy = 0; + } + + const sub = Vector.sub(this.lockedOn.position, this.position) + const DIST = Vector.magnitude(sub); + const unit = Vector.normalise(sub) + if (DIST < mod.isPlasmaRange * 600) { + //calculate laser collision + let best; + let range = mod.isPlasmaRange * (140 + 300 * Math.sqrt(Math.random())) + const path = [{ + x: this.position.x, + y: this.position.y + }, + { + x: this.position.x + range * unit.x, + y: this.position.y + range * unit.y + } + ]; + const vertexCollision = function (v1, v1End, domain) { + for (let i = 0; i < domain.length; ++i) { + let vertices = domain[i].vertices; + const len = vertices.length - 1; + for (let j = 0; j < len; j++) { + results = game.checkLineIntersection(v1, v1End, vertices[j], vertices[j + 1]); + if (results.onLine1 && results.onLine2) { + const dx = v1.x - results.x; + const dy = v1.y - results.y; + const dist2 = dx * dx + dy * dy; + if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) { + best = { + x: results.x, + y: results.y, + dist2: dist2, + who: domain[i], + v1: vertices[j], + v2: vertices[j + 1] + }; + } + } + } + results = game.checkLineIntersection(v1, v1End, vertices[0], vertices[len]); + if (results.onLine1 && results.onLine2) { + const dx = v1.x - results.x; + const dy = v1.y - results.y; + const dist2 = dx * dx + dy * dy; + if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) { + best = { + x: results.x, + y: results.y, + dist2: dist2, + who: domain[i], + v1: vertices[0], + v2: vertices[len] + }; + } + } + } + }; + + //check for collisions + best = { + x: null, + y: null, + dist2: Infinity, + who: null, + v1: null, + v2: null + }; + vertexCollision(path[0], path[1], mob); + vertexCollision(path[0], path[1], map); + vertexCollision(path[0], path[1], body); + if (best.dist2 != Infinity) { //if hitting something + path[path.length - 1] = { + x: best.x, + y: best.y + }; + if (best.who.alive) { + const dmg = 0.8 * b.dmgScale; //********** SCALE DAMAGE HERE ********************* + best.who.damage(dmg); + best.who.locatePlayer(); + + //push mobs away + const force = Vector.mult(Vector.normalise(Vector.sub(mech.pos, path[1])), -0.01 * Math.min(5, best.who.mass)) + Matter.Body.applyForce(best.who, path[1], force) + Matter.Body.setVelocity(best.who, { //friction + x: best.who.velocity.x * 0.7, + y: best.who.velocity.y * 0.7 + }); + //draw mob damage circle + game.drawList.push({ + x: path[1].x, + y: path[1].y, + radius: Math.sqrt(dmg) * 50, + color: "rgba(255,0,255,0.2)", + time: game.drawTime * 4 + }); + } else if (!best.who.isStatic) { + //push blocks away + const force = Vector.mult(Vector.normalise(Vector.sub(mech.pos, path[1])), -0.007 * Math.sqrt(Math.sqrt(best.who.mass))) + Matter.Body.applyForce(best.who, path[1], force) + } + } + + //draw blowtorch laser beam + ctx.strokeStyle = "rgba(255,0,255,0.1)" + ctx.lineWidth = 14 + ctx.beginPath(); + ctx.moveTo(path[0].x, path[0].y); + ctx.lineTo(path[1].x, path[1].y); + ctx.stroke(); + ctx.strokeStyle = "#f0f"; + ctx.lineWidth = 2 + ctx.stroke(); + + //draw electricity + const Dx = Math.cos(mech.angle); + const Dy = Math.sin(mech.angle); + let x = this.position.x + 20 * Dx; + let y = this.position.y + 20 * Dy; + ctx.beginPath(); + ctx.moveTo(x, y); + const step = Vector.magnitude(Vector.sub(path[0], path[1])) / 5 + for (let i = 0; i < 4; i++) { + x += step * (Dx + 1.5 * (Math.random() - 0.5)) + y += step * (Dy + 1.5 * (Math.random() - 0.5)) + ctx.lineTo(x, y); + } + ctx.lineWidth = 2 * Math.random(); + ctx.stroke(); + } + } + } + }) + World.add(engine.world, bullet[me]); //add bullet to world + }, + boomBot(position = mech.pos) { + const me = bullet.length; + const dir = mech.angle; + const RADIUS = (7 + 2 * Math.random()) + bullet[me] = Bodies.polygon(position.x, position.y, 4, RADIUS, { + angle: dir, + friction: 0, + frictionStatic: 0, + frictionAir: 0.05, + restitution: 1, + dmg: 0, + minDmgSpeed: 0, + lookFrequency: 35 + Math.floor(7 * Math.random()), + acceleration: 0.005 * (1 + 0.5 * Math.random()), + range: 500 * (1 + 0.1 * Math.random()), + endCycle: Infinity, + classType: "bullet", + collisionFilter: { + category: cat.bullet, + mask: cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet | cat.mobShield + }, + lockedOn: null, + explode: 0, + onDmg() { + if (this.lockedOn) { + const explosionRadius = Math.min(170, Vector.magnitude(Vector.sub(this.position, mech.pos)) - 30) + if (explosionRadius > 60) { + this.explode = explosionRadius + // + //push away from player, because normal explosion knock doesn't do much + // const sub = Vector.sub(this.lockedOn.position, mech.pos) + // mag = Math.min(35, 20 / Math.sqrt(this.lockedOn.mass)) + // Matter.Body.setVelocity(this.lockedOn, Vector.mult(Vector.normalise(sub), mag)) + } + this.lockedOn = null //lose target so bot returns to player + } + }, + onEnd() {}, + do() { + if (this.explode) { + b.explosion(this.position, this.explode); //makes bullet do explosive damage at end + this.explode = 0; + } + const distanceToPlayer = Vector.magnitude(Vector.sub(this.position, mech.pos)) + if (distanceToPlayer > 100) { //if far away move towards player + this.force = Vector.mult(Vector.normalise(Vector.sub(mech.pos, this.position)), this.mass * this.acceleration) + } else if (distanceToPlayer < 250) { //close to player + Matter.Body.setVelocity(this, Vector.add(Vector.mult(this.velocity, 0.90), Vector.mult(player.velocity, 0.17))); //add player's velocity + //find targets + if (!(game.cycle % this.lookFrequency) && !mech.isStealth) { + this.lockedOn = null; + let closeDist = this.range; + for (let i = 0, len = mob.length; i < len; ++i) { + const DIST = Vector.magnitude(Vector.sub(this.position, mob[i].position)) - mob[i].radius; + if (DIST < closeDist && mob[i].dropPowerUp && + Matter.Query.ray(map, this.position, mob[i].position).length === 0 && + Matter.Query.ray(body, this.position, mob[i].position).length === 0) { + closeDist = DIST; + this.lockedOn = mob[i] + } + } + } + } + //punch target + if (this.lockedOn && this.lockedOn.alive) { + const DIST = Vector.magnitude(Vector.sub(this.vertices[0], this.lockedOn.position)); + if (DIST - this.lockedOn.radius < this.range && + Matter.Query.ray(map, this.position, this.lockedOn.position).length === 0) { + //move towards the target + this.force = Vector.add(this.force, Vector.mult(Vector.normalise(Vector.sub(this.lockedOn.position, this.position)), 0.012 * this.mass)) + } + } + } + }) + World.add(engine.world, bullet[me]); //add bullet to world + }, laserBot(position = mech.pos) { const me = bullet.length; const dir = mech.angle; @@ -2212,7 +2479,7 @@ const b = { }, { name: "drones", - description: "deploy drones that crash into mobs
collisions reduce their lifespan by 1 second", + description: "deploy drones that crash into mobs
crashes reduce their lifespan by 1 second", ammo: 0, ammoPack: 14, have: false, @@ -2660,7 +2927,7 @@ const b = { isEasyToAim: false, fire() { //calculate laser collision - let best; + let best, energy, explosionRange; let range = 3000 const path = [{ x: mech.pos.x + 20 * Math.cos(mech.angle), @@ -2722,15 +2989,22 @@ const b = { v2: null }; if (mod.isPulseAim) { //find mobs in line of sight + let dist = 2200 + energy = 0.25 * Math.min(mech.energy, 1.75) + explosionRange = 1000 * energy for (let i = 0, len = mob.length; i < len; i++) { - if (Vector.magnitude(Vector.sub(path[0], mob[i].position)) < 2200 && + const newDist = Vector.magnitude(Vector.sub(path[0], mob[i].position)) + if (explosionRange < newDist && + newDist < dist && Matter.Query.ray(map, path[0], mob[i].position).length === 0 && Matter.Query.ray(body, path[0], mob[i].position).length === 0) { + dist = newDist best.who = mob[i] path[path.length - 1] = mob[i].position - break } } + + } if (!best.who) { vertexCollision(path[0], path[1], mob); @@ -2743,16 +3017,16 @@ const b = { }; } } - let energy + if (mod.isPulseAim) { - energy = 0.25 * Math.min(mech.energy, 1.75) mech.energy -= energy * mod.isLaserDiode - if (best.who) b.explosion(path[1], 1000 * energy, true) + if (best.who) b.explosion(path[1], explosionRange, true) mech.fireCDcycle = mech.cycle + Math.floor(25 * b.fireCD); // cool down } else { energy = 0.3 * Math.min(mech.energy, 1.75) mech.energy -= energy * mod.isLaserDiode - if (best.who) b.explosion(path[1], 1000 * energy, true) + explosionRange = 1000 * energy + if (best.who) b.explosion(path[1], explosionRange, true) mech.fireCDcycle = mech.cycle + Math.floor(50 * b.fireCD); // cool down } if (mod.isPulseStun) { diff --git a/js/engine.js b/js/engine.js index 9eab081..599e6aa 100644 --- a/js/engine.js +++ b/js/engine.js @@ -208,7 +208,7 @@ function collisionChecks(event) { if (mod.isCrit && !mob[k].seePlayer.recall && !mob[k].shield) dmg *= 5 mob[k].foundPlayer(); mob[k].damage(dmg); - obj.onDmg(mob[k]); //some bullets do actions when they hits things, like despawn + obj.onDmg(mob[k]); //some bullets do actions when they hits things, like despawn //forces don't seem to work here game.drawList.push({ //add dmg to draw queue x: pairs[i].activeContacts[0].vertex.x, y: pairs[i].activeContacts[0].vertex.y, diff --git a/js/game.js b/js/game.js index 1725a51..61ff2f8 100644 --- a/js/game.js +++ b/js/game.js @@ -2,33 +2,6 @@ //********************************************************************* const game = { loop() {}, //main game loop, gets se tto normal or testing loop - testingLoop() { - game.gravity(); - Engine.update(engine, game.delta); - game.wipe(); - game.textLog(); - if (mech.onGround) { - mech.groundControl() - } else { - mech.airControl() - } - level.checkZones(); - level.checkQuery(); - mech.move(); - mech.look(); - game.checks(); - ctx.save(); - game.camera(); - mech.draw(); - game.draw.wireFrame(); - game.draw.cons(); - game.draw.testing(); - game.drawCircle(); - game.constructCycle() - ctx.restore(); - game.testingOutput(); - game.drawCursor(); - }, normalLoop() { game.gravity(); Engine.update(engine, game.delta); @@ -39,7 +12,8 @@ const game = { } else { mech.airControl() } - level.checkZones(); + // level.checkZones(); + level.custom(); level.checkQuery(); mech.move(); mech.look(); @@ -65,10 +39,38 @@ const game = { b.bulletDraw(); b.bulletDo(); game.drawCircle(); - game.clip(); + // game.clip(); ctx.restore(); game.drawCursor(); }, + testingLoop() { + game.gravity(); + Engine.update(engine, game.delta); + game.wipe(); + game.textLog(); + if (mech.onGround) { + mech.groundControl() + } else { + mech.airControl() + } + // level.checkZones(); + level.custom(); + level.checkQuery(); + mech.move(); + mech.look(); + game.checks(); + ctx.save(); + game.camera(); + mech.draw(); + game.draw.wireFrame(); + game.draw.cons(); + game.draw.testing(); + game.drawCircle(); + game.constructCycle() + ctx.restore(); + game.testingOutput(); + game.drawCursor(); + }, isTimeSkipping: false, timeSkip(cycles = 60) { game.isTimeSkipping = true; @@ -146,9 +148,9 @@ const game = { // }; // requestAnimationFrame(normalFPS); // }, - clip() { + // clip() { - }, + // }, drawCursor() { const size = 10; ctx.beginPath(); @@ -397,7 +399,7 @@ const game = { }); // game.noCameraScroll() } else if (keys[85]) { // next level with U - level.zoneActions.nextLevel(); + level.nextLevel(); } } }, @@ -659,11 +661,9 @@ const game = { powerUps.totalPowerUps = powerUp.length - //if player is holding something this remembers it before it gets deleted - let holdTarget; - if (mech.holdingTarget) { - holdTarget = mech.holdingTarget; - } + let holdTarget; //if player is holding something this remembers it before it gets deleted + if (mech.holdingTarget) holdTarget = mech.holdingTarget; + mech.fireCDcycle = 0 mech.drop(); level.fill = []; @@ -697,7 +697,11 @@ const game = { frictionAir: holdTarget.frictionAir, frictionStatic: holdTarget.frictionStatic }); + Matter.Body.setPosition(body[len], mech.pos); + mech.isHolding = true mech.holdingTarget = body[len]; + mech.holdingTarget.collisionFilter.category = 0; + mech.holdingTarget.collisionFilter.mask = 0; } }, getCoords: { @@ -811,20 +815,20 @@ const game = { let line = 500; const x = canvas.width - 5; ctx.fillText("T: exit testing mode", x, line); - line += 20; - ctx.fillText("Y: give all mods", x, line); - line += 20; - ctx.fillText("R: teleport to mouse", x, line); - line += 20; - ctx.fillText("F: cycle field", x, line); - line += 20; - ctx.fillText("G: give all guns", x, line); - line += 20; - ctx.fillText("H: heal", x, line); - line += 20; - ctx.fillText("U: next level", x, line); - line += 20; - ctx.fillText("1-7: spawn things", x, line); + // line += 20; + // ctx.fillText("Y: give all mods", x, line); + // line += 20; + // ctx.fillText("R: teleport to mouse", x, line); + // line += 20; + // ctx.fillText("F: cycle field", x, line); + // line += 20; + // ctx.fillText("G: give all guns", x, line); + // line += 20; + // ctx.fillText("H: heal", x, line); + // line += 20; + // ctx.fillText("U: next level", x, line); + // line += 20; + // ctx.fillText("1-7: spawn things", x, line); } ctx.textAlign = "center"; ctx.fillText(`(${game.mouseInGame.x.toFixed(1)}, ${game.mouseInGame.y.toFixed(1)})`, game.mouse.x, game.mouse.y - 20); @@ -924,13 +928,6 @@ const game = { ctx.stroke(); }, testing() { - //zones - ctx.beginPath(); - for (let i = 0, len = level.zones.length; i < len; ++i) { - ctx.rect(level.zones[i].x1, level.zones[i].y1 + 70, level.zones[i].x2 - level.zones[i].x1, level.zones[i].y2 - level.zones[i].y1); - } - ctx.fillStyle = "rgba(0, 255, 0, 0.3)"; - ctx.fill(); //query zones ctx.beginPath(); for (let i = 0, len = level.queryList.length; i < len; ++i) { diff --git a/js/level.js b/js/level.js index 8c2b641..031c00a 100644 --- a/js/level.js +++ b/js/level.js @@ -1,29 +1,28 @@ -//global game variables let body = []; //non static bodies let map = []; //all static bodies let cons = []; //all constraints between a point and a body let consBB = []; //all constraints between two bodies -//main object for spawning levels const level = { - maxJump: 390, defaultZoom: 1400, - boostScale: 0.000023, - levels: ["skyscrapers", "rooftops", "warehouse", "highrise", "office", "aerie", "satellite"], onLevel: 0, levelsCleared: 0, + levels: ["skyscrapers", "rooftops", "warehouse", "highrise", "office", "aerie", "satellite"], start() { if (build.isURLBuild && level.levelsCleared === 0) build.onLoadPowerUps(); if (level.levelsCleared === 0) { //this code only runs on the first level // game.enableConstructMode() //used to build maps in testing mode // level.difficultyIncrease(9) // mech.isStealth = true; - // mod.giveMod("logistics"); + // mod.giveMod("plasma-bot"); + // mod.giveMod("nail-bot"); + // mod.giveMod("laser-bot"); + // mod.giveMod("boom-bot"); // mod.giveMod("supply chain"); // b.giveGuns("pulse") - // mech.setField("phase decoherence field") + // mech.setField("plasma torch") level.intro(); //starting level - // level.testing(); + // level.testing(); // level.stronghold() // level.bosses(); // level.satellite(); @@ -53,6 +52,13 @@ const level = { for (let i = 0; i < mod.foamBotCount; i++) { b.foamBot() } + for (let i = 0; i < mod.boomBotCount; i++) { + b.boomBot() + } + for (let i = 0; i < mod.plasmaBotCount; i++) { + b.plasmaBot() + } + if (mod.isArmorFromPowerUps) { // for (let i = 0; i < powerUps.totalPowerUps; i++) {} mech.maxHealth += 0.04 * powerUps.totalPowerUps @@ -85,31 +91,6 @@ const level = { if (game.difficulty < 1) game.difficulty = 0; game.healScale = 1 / (1 + game.difficulty * 0.09) }, - // difficultyIncrease(num = 1) { - // // if (level.isBuildRun) num++ - // for (let i = 0; i < num; i++) { - // game.difficulty++ - // game.dmgScale += 0.17; //damage done by mobs increases each level - // b.dmgScale *= 0.91; //damage done by player decreases each level - // game.accelScale *= 1.02 //mob acceleration increases each level - // game.lookFreqScale *= 0.98 //mob cycles between looks decreases each level - // game.CDScale *= 0.97 //mob CD time decreases each level - // } - // game.healScale = 1 / (1 + game.difficulty * 0.09) //a higher denominator makes for lower heals // mech.health += heal * game.healScale; - // }, - // difficultyDecrease(num = 1) { //used in easy mode for game.reset() - // for (let i = 0; i < num; i++) { - // game.difficulty-- - // game.dmgScale -= 0.17; //damage done by mobs increases each level - // if (game.dmgScale < 0.1) game.dmgScale = 0.1; - // b.dmgScale /= 0.91; //damage done by player decreases each level - // game.accelScale /= 1.02 //mob acceleration increases each level - // game.lookFreqScale /= 0.98 //mob cycles between looks decreases each level - // game.CDScale /= 0.97 //mob CD time decreases each level - // } - // if (game.difficulty < 1) game.difficulty = 0; - // game.healScale = 1 / (1 + game.difficulty * 0.09) - // }, difficultyText(mode = document.getElementById("difficulty-select").value) { if (mode === "0") { return "easy" @@ -128,10 +109,207 @@ const level = { document.title = "n-gon: L" + (level.levelsCleared) + " " + level.levels[level.onLevel] + " (" + level.difficultyText() + ")"; } }, - //****************************************************************************************************************** - //****************************************************************************************************************** + custom() {}, //each level runs it's own custom code (level exits, ...) + nextLevel() { + level.levelsCleared++; + level.onLevel++; //cycles map to next level + if (level.onLevel > level.levels.length - 1) level.onLevel = 0; + level.difficultyIncrease(game.difficultyMode) //increase difficulty based on modes + if (game.isEasyMode && level.levelsCleared % 2) level.difficultyDecrease(1); + game.clearNow = true; //triggers in game.clearMap to remove all physics bodies and setup for new map + }, + playerExitCheck() { + if ( + player.position.x > level.exit.x && + player.position.x < level.exit.x + 100 && + player.position.y > level.exit.y - 150 && + player.position.y < level.exit.y - 40 && + player.velocity.y < 0.1 + ) { + level.nextLevel() + } + }, + setPosToSpawn(xPos, yPos) { + mech.spawnPos.x = mech.pos.x = xPos; + mech.spawnPos.y = mech.pos.y = yPos; + level.enter.x = mech.spawnPos.x - 50; + level.enter.y = mech.spawnPos.y + 20; + mech.transX = mech.transSmoothX = canvas.width2 - mech.pos.x; + mech.transY = mech.transSmoothY = canvas.height2 - mech.pos.y; + mech.Vx = mech.spawnVel.x; + mech.Vy = mech.spawnVel.y; + player.force.x = 0; + player.force.y = 0; + Matter.Body.setPosition(player, mech.spawnPos); + Matter.Body.setVelocity(player, mech.spawnVel); + }, + enter: { + x: 0, + y: 0, + draw() { + ctx.beginPath(); + ctx.moveTo(level.enter.x, level.enter.y + 30); + ctx.lineTo(level.enter.x, level.enter.y - 80); + ctx.bezierCurveTo(level.enter.x, level.enter.y - 170, level.enter.x + 100, level.enter.y - 170, level.enter.x + 100, level.enter.y - 80); + ctx.lineTo(level.enter.x + 100, level.enter.y + 30); + ctx.lineTo(level.enter.x, level.enter.y + 30); + ctx.fillStyle = "#ccc"; + ctx.fill(); + } + }, + exit: { + x: 0, + y: 0, + draw() { + ctx.beginPath(); + ctx.moveTo(level.exit.x, level.exit.y + 30); + ctx.lineTo(level.exit.x, level.exit.y - 80); + ctx.bezierCurveTo(level.exit.x, level.exit.y - 170, level.exit.x + 100, level.exit.y - 170, level.exit.x + 100, level.exit.y - 80); + ctx.lineTo(level.exit.x + 100, level.exit.y + 30); + ctx.lineTo(level.exit.x, level.exit.y + 30); + ctx.fillStyle = "#0ff"; + ctx.fill(); + } + }, + fillBG: [], + drawFillBGs() { + 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() { + 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); + } + }, + queryList: [], //queries do actions on many objects in regions + checkQuery() { + 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(x, y, width, height, action, groups = [ + [player], body, mob, powerUp, bullet + ], info) { + level.queryList[level.queryList.length] = { + bounds: { + min: { + x: x, + y: y + }, + max: { + x: x + width, + y: y + height + } + }, + action: action, + groups: groups, + info: info + }; + }, + queryActions: { + bounce(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(target, yVelocity) { + // if (target.velocity.y < 0) { + // mech.undoCrouch(); + // mech.enterAir(); + mech.buttonCD_jump = 0; // reset short jump counter to prevent short jumps on boosts + mech.hardLandCD = 0 // disable hard landing + if (target.velocity.y > 30) { + Matter.Body.setVelocity(target, { + x: target.velocity.x + (Math.random() - 0.5) * 2, + y: -23 //gentle bounce if coming down super fast + }); + } else { + Matter.Body.setVelocity(target, { + x: target.velocity.x + (Math.random() - 0.5) * 2, + y: yVelocity + }); + } + + }, + force(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(target) { + target.force.y -= 0.0011 * target.mass; + }, + death(target) { + target.death(); + } + }, + addToWorld() { + //needs to be run to put bodies into the world + for (let i = 0; i < body.length; i++) { + //body[i].collisionFilter.group = 0; + if (body[i] !== mech.holdingTarget) { + body[i].collisionFilter.category = cat.body; + body[i].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet + } + 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 = cat.map; + map[i].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet; + 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]); + } + }, + //****************************************************************************************************************** + //****************************************************************************************************************** + //****************************************************************************************************************** + //****************************************************************************************************************** testing() { + level.custom = () => { + level.playerExitCheck(); + }; + + level.setPosToSpawn(0, -750); //normal spawn + spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); + level.exit.x = 6500; + level.exit.y = -230; + // level.difficultyIncrease(14); //hard mode level 7 spawn.setSpawnList(); spawn.setSpawnList(); @@ -150,13 +328,7 @@ const level = { color: "rgba(0,255,255,0.1)" }); - mech.setPosToSpawn(0, -750); //normal spawn - level.enter.x = mech.spawnPos.x - 50; - level.enter.y = mech.spawnPos.y + 20; - spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); - level.exit.x = 6500; - level.exit.y = -230; - level.addZone(level.exit.x, level.exit.y, 100, 30, "nextLevel"); + // level.addZone(level.exit.x, level.exit.y, 100, 30, "nextLevel"); spawn.mapRect(-950, 0, 8200, 800); //ground spawn.mapRect(-950, -1200, 800, 1400); //left wall @@ -205,29 +377,18 @@ const level = { // spawn.randomMob(1600, -500) }, bosses() { + level.custom = () => { + level.playerExitCheck(); + }; + + level.setPosToSpawn(0, -750); //normal spawn + spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); + level.exit.x = 6500; + level.exit.y = -230; + level.defaultZoom = 1500 game.zoomTransition(level.defaultZoom) - - // spawn.setSpawnList(); - // spawn.setSpawnList(); - // game.difficulty = 7; //for testing to simulate all possible mobs spawns - // for (let i = 0; i < game.difficulty; i++) { - // game.dmgScale += 0.4; //damage done by mobs increases each level - // b.dmgScale *= 0.9; //damage done by player decreases each level - // } - document.body.style.backgroundColor = "#ddd"; - // game.draw.mapFill = "#444" - // game.draw.bodyFill = "rgba(140,140,140,0.85)" - // game.draw.bodyStroke = "#222" - - // level.fillBG.push({ - // x: -150, - // y: -1150, - // width: 7000, - // height: 1200, - // color: "#eee" - // }); level.fill.push({ x: 6400, @@ -237,15 +398,6 @@ const level = { color: "rgba(0,255,255,0.1)" }); - mech.setPosToSpawn(0, -750); //normal spawn - level.enter.x = mech.spawnPos.x - 50; - level.enter.y = mech.spawnPos.y + 20; - spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); - - level.exit.x = 6500; - level.exit.y = -230; - level.addZone(level.exit.x, level.exit.y, 100, 30, "nextLevel"); - spawn.mapRect(-950, 0, 8200, 800); //ground spawn.mapRect(-950, -1200, 800, 1400); //left wall spawn.mapRect(-950, -1800, 8200, 800); //roof @@ -284,23 +436,22 @@ const level = { } }, intro() { - // b.giveGuns(0, 1000) + level.custom = () => { + level.playerExitCheck(); + }; + + level.setPosToSpawn(460, -100); //normal spawn + level.enter.x = -1000000; //hide enter graphic for first level by moving to the far left + level.exit.x = 2800; + level.exit.y = -335; + spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump + game.zoomScale = 1000 //1400 is normal level.defaultZoom = 1600 game.zoomTransition(level.defaultZoom, 1) - mech.setPosToSpawn(460, -100); //normal spawn - level.enter.x = -1000000; //offscreen - level.enter.y = -400; - level.exit.x = 2800; - level.exit.y = -335; - level.addZone(level.exit.x, level.exit.y, 100, 30, "nextLevel"); - spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump document.body.style.backgroundColor = "#ddd"; - // game.draw.mapFill = "#444" - // game.draw.bodyFill = "rgba(140,140,140,0.85)" - // game.draw.bodyStroke = "#222" level.fill.push({ x: 2600, @@ -317,14 +468,6 @@ const level = { color: "#fff" }); - // level.fill.push({ - // x: -150, - // y: -1000, - // width: 2750, - // height: 1000, - // color: "rgba(0,10,30,0.04)" - // }); - const lineColor = "#ccc" level.fillBG.push({ x: 1600, @@ -397,20 +540,6 @@ const level = { spawn.mapRect(-95, -1100, 80, 110); //wire source spawn.mapRect(410, -10, 90, 20); //small platform for player - // spawn.bodyRect(-35, -50, 50, 50); - // spawn.bodyRect(-40, -100, 50, 50); - // spawn.bodyRect(-45, -150, 60, 50); - // spawn.bodyRect(-40, -200, 50, 50); - // spawn.bodyRect(5, -50, 40, 50); - // spawn.bodyRect(10, -100, 60, 50); - // spawn.bodyRect(-10, -150, 40, 50); - // spawn.bodyRect(55, -100, 40, 50); - // spawn.bodyRect(-150, -300, 100, 100); - // spawn.bodyRect(-150, -200, 100, 100); - // spawn.bodyRect(-150, -100, 100, 100); - - // spawn.bodyRect(1790, -50, 40, 50); - // spawn.bodyRect(1875, -100, 200, 90); spawn.bodyRect(2425, -120, 70, 50); spawn.bodyRect(2400, -100, 100, 60); spawn.bodyRect(2500, -150, 100, 150); //exit step @@ -423,38 +552,24 @@ const level = { // powerUps.spawn(2050, -150, "field", false); //starting gun powerUps.spawnStartingPowerUps(2300, -150); - // powerUps.spawn(2300, -150, "gun", false); //starting gun - // if (game.isEasyMode) { - // // powerUps.spawn(2050, -150, "mod", false); //starting gun - // // powerUps.spawn(2050, -150, "mod", false); //starting gun - // // powerUps.spawn(-100, -150, "ammo", false); //starting gun - // powerUps.spawn(-100, 0, "heal", false); //starting gun - // } - spawn.wireFoot(); spawn.wireFootLeft(); spawn.wireKnee(); spawn.wireKneeLeft(); spawn.wireHead(); - // spawn.mapRect(1400, -700, 50, 300); //ground - // spawn.healer(1600, -500) - // spawn.healer(1600, -500) - // spawn.healer(1900, -500) - // spawn.healer(1000, -500) - // spawn.healer(1000, -400) }, satellite() { - // game.zoomScale = 4500 // remove - level.defaultZoom = 1700 // 4500 // 1400 - game.zoomTransition(level.defaultZoom) - mech.setPosToSpawn(-50, -50); //normal spawn - level.enter.x = mech.spawnPos.x - 50; - level.enter.y = mech.spawnPos.y + 20; + level.custom = () => { + level.playerExitCheck(); + }; + + level.setPosToSpawn(-50, -50); //normal spawn level.exit.x = -100; level.exit.y = -425; - level.addZone(level.exit.x, level.exit.y, 100, 30, "nextLevel"); spawn.mapRect(level.exit.x, level.exit.y + 15, 100, 50); //exit bump + level.defaultZoom = 1700 // 4500 // 1400 + game.zoomTransition(level.defaultZoom) powerUps.spawnStartingPowerUps(4450, -1400); spawn.debris(1000, 20, 1800, 3); //16 debris per level //but less here because a few mobs die from laser @@ -462,9 +577,6 @@ const level = { spawn.debris(3035, -3900, 1500, 3); //16 debris per level document.body.style.backgroundColor = "#dbdcde"; - // game.draw.mapFill = "#444" - // game.draw.bodyFill = "rgba(140,140,140,0.85)" - // game.draw.bodyStroke = "#222" //spawn start building spawn.mapRect(-300, -800, 50, 800); @@ -643,16 +755,18 @@ const level = { } }, rooftops() { + level.custom = () => { + level.playerExitCheck(); + }; + level.defaultZoom = 1700 game.zoomTransition(level.defaultZoom) document.body.style.backgroundColor = "#dcdcde"; - // game.draw.mapFill = "#444" - // game.draw.bodyFill = "rgba(140,140,140,0.85)" - // game.draw.bodyStroke = "#222" + if (Math.random() < 0.75) { //normal direction start in top left - mech.setPosToSpawn(-450, -2060); + level.setPosToSpawn(-450, -2060); level.exit.x = 3600; level.exit.y = -300; spawn.mapRect(3600, -285, 100, 50); //ground bump wall @@ -677,7 +791,7 @@ const level = { }); } else { //reverse direction, start in bottom right - mech.setPosToSpawn(3650, -325); + level.setPosToSpawn(3650, -325); level.exit.x = -550; level.exit.y = -2030; spawn.mapRect(-550, -2015, 100, 50); //ground bump wall @@ -697,10 +811,7 @@ const level = { color: "rgba(0,0,0,0.1)" }); } - level.enter.x = mech.spawnPos.x - 50; - level.enter.y = mech.spawnPos.y + 20; spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); - level.addZone(level.exit.x, level.exit.y, 100, 30, "nextLevel"); spawn.debris(1650, -1800, 3800, 16); //16 debris per level powerUps.spawnStartingPowerUps(2450, -1675); @@ -843,10 +954,12 @@ const level = { spawn.randomBoss(600, -1575, 0); spawn.randomBoss(2225, -1325, 0.4); spawn.randomBoss(4900, -1200, 0); - //spawn.randomBoss(4850, -1250,0.7); if (game.difficulty > 3) spawn.randomLevelBoss(3200, -2050); }, aerie() { + level.custom = () => { + level.playerExitCheck(); + }; // game.setZoom(3000); // game.difficulty = 4; //for testing to simulate possible mobs spawns level.defaultZoom = 2100 @@ -854,33 +967,24 @@ const level = { const backwards = (Math.random() < 0.25 && game.difficulty > 8) ? true : false; if (backwards) { - mech.setPosToSpawn(4000, -3300); //normal spawn + level.setPosToSpawn(4000, -3300); //normal spawn level.exit.x = -100; level.exit.y = -1025; } else { - mech.setPosToSpawn(-50, -1050); //normal spawn + level.setPosToSpawn(-50, -1050); //normal spawn level.exit.x = 3950; level.exit.y = -3275; } - // mech.setPosToSpawn(2250, -900); - // game.zoomTransition(1500) //1400 is normal - level.enter.x = mech.spawnPos.x - 50; - level.enter.y = mech.spawnPos.y + 20; spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); spawn.mapRect(level.exit.x, level.exit.y + 15, 100, 20); - // spawn.mapRect(3950, -3260, 100, 30); - level.addZone(level.exit.x, level.exit.y, 100, 30, "nextLevel"); powerUps.spawnStartingPowerUps(1075, -550); spawn.debris(-250, 50, 1650, 2); //16 debris per level spawn.debris(2475, 0, 750, 2); //16 debris per level spawn.debris(3450, 0, 2000, 16); //16 debris per level spawn.debris(3500, -2350, 1500, 2); //16 debris per level document.body.style.backgroundColor = "#dcdcde"; - // game.draw.mapFill = "#444" - // game.draw.bodyFill = "rgba(140,140,140,0.85)" - // game.draw.bodyStroke = "#222" //foreground level.fill.push({ @@ -1046,19 +1150,20 @@ const level = { //add mini boss, giant hopper? or a black hole that spawns hoppers? }, skyscrapers() { + level.custom = () => { + level.playerExitCheck(); + }; + + level.setPosToSpawn(-50, -60); //normal spawn + spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); + level.exit.x = 1500; + level.exit.y = -1875; + level.defaultZoom = 2000 game.zoomTransition(level.defaultZoom) - mech.setPosToSpawn(-50, -60); //normal spawn - //mech.setPosToSpawn(1550, -1200); //spawn left high - //mech.setPosToSpawn(1800, -2000); //spawn near exit - level.enter.x = mech.spawnPos.x - 50; - level.enter.y = mech.spawnPos.y + 20; - spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); - - level.exit.x = 1500; - level.exit.y = -1875; - level.addZone(level.exit.x, level.exit.y, 100, 30, "nextLevel"); + //level.setPosToSpawn(1550, -1200); //spawn left high + //level.setPosToSpawn(1800, -2000); //spawn near exit powerUps.spawnStartingPowerUps(1475, -1175); spawn.debris(750, -2200, 3700, 16); //16 debris per level @@ -1203,32 +1308,25 @@ const level = { if (game.difficulty > 3) spawn.randomLevelBoss(2200, -1300); }, highrise() { + level.custom = () => { + level.playerExitCheck(); + }; + + level.setPosToSpawn(0, -700); //normal spawn + spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); + level.exit.x = -4275; + level.exit.y = -2805; + level.defaultZoom = 1500 game.zoomTransition(level.defaultZoom) - mech.setPosToSpawn(0, -700); //normal spawn - //mech.setPosToSpawn(-2000, -1700); // left ledge spawn - level.enter.x = mech.spawnPos.x - 50; - level.enter.y = mech.spawnPos.y + 20; - spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); - - level.exit.x = -4275; - level.exit.y = -2805; - level.addZone(level.exit.x, level.exit.y, 100, 30, "nextLevel"); powerUps.spawnStartingPowerUps(-2550, -700); document.body.style.backgroundColor = "#dcdcde" //"#fafcff"; - // game.draw.mapFill = "#444" - // game.draw.bodyFill = "rgba(140,140,140,0.85)" - // game.draw.bodyStroke = "#222" - // spawn.laserZone(-550, -350, 10, 400, 0.3) - // spawn.deathQuery(-550, -350, 50, 400) - - // spawn.debris(-3950, -2575, 1050, 4); //16 debris per level spawn.debris(-2325, -1825, 2400); //16 debris per level spawn.debris(-2625, -600, 600, 5); //16 debris per level spawn.debris(-2000, -60, 1200, 5); //16 debris per level - // if (!game.difficulty) powerUps.spawn(2450, -1675, "gun", false); + //background level.fillBG.push({ x: -4425, @@ -1275,20 +1373,13 @@ const level = { height: 360, color: "rgba(64,64,64,0.97)" }); - // level.fill.push({ - // x: -4050, - // y: -955, - // width: 625, - // height: 360, - // color: "#444" - // }); + powerUps.spawn(-4300, -700, "heal"); powerUps.spawn(-4200, -700, "ammo"); powerUps.spawn(-4000, -700, "ammo"); spawn.mapRect(-4450, -1000, 100, 500); spawn.bodyRect(-3576, -750, 150, 150); - //building 1 spawn.bodyRect(-1000, -675, 25, 25); spawn.mapRect(-2225, 0, 2475, 150); @@ -1307,10 +1398,8 @@ const level = { spawn.mapRect(-1125, -1575, 50, 475); spawn.bodyRect(-1475, -1275, 250, 125); spawn.bodyRect(-825, -1160, 250, 10); - spawn.mapRect(-1650, -1575, 400, 50); spawn.mapRect(-600, -1150, 850, 175); - spawn.mapRect(-1850, -1150, 1050, 175); spawn.bodyRect(-1907, -1600, 550, 25); if (game.difficulty < 4) { @@ -1320,10 +1409,6 @@ const level = { spawn.bodyRect(-1200, -125, 125, 125); spawn.bodyRect(-1160, -200, 75, 75); } - // spawn.bodyRect(-1100, -125, 150, 125); - - // spawn.bodyRect(-1200, -75, 75, 75); - //building 2 spawn.mapRect(-4450, -600, 2300, 750); spawn.mapRect(-2225, -500, 175, 550); @@ -1338,7 +1423,6 @@ const level = { spawn.bodyRect(-3415, -1425, 100, 100); spawn.bodyRect(-3400, -1525, 100, 100); spawn.bodyRect(-3305, -1425, 100, 100); - //building 3 spawn.mapRect(-4450, -1750, 1025, 1000); spawn.mapRect(-3750, -2000, 175, 275); @@ -1348,7 +1432,6 @@ const level = { spawn.bodyRect(-3715, -2050, 50, 50); spawn.bodyRect(-3570, -1800, 50, 50); spawn.bodyRect(-2970, -2250, 50, 50); - spawn.bodyRect(-3080, -2250, 40, 40); spawn.bodyRect(-3420, -650, 50, 50); @@ -1387,31 +1470,23 @@ const level = { if (game.difficulty > 4) spawn.randomLevelBoss(-3400, -2800); }, warehouse() { - level.defaultZoom = 1300 - game.zoomTransition(level.defaultZoom) + level.custom = () => { + level.playerExitCheck(); + }; - mech.setPosToSpawn(25, -55); //normal spawn - //mech.setPosToSpawn(-2000, -1700); // left ledge spawn - level.enter.x = mech.spawnPos.x - 50; - level.enter.y = mech.spawnPos.y + 20; + level.setPosToSpawn(25, -55); //normal spawn level.exit.x = 425; level.exit.y = -30; - level.addZone(level.exit.x, level.exit.y, 100, 30, "nextLevel"); - //level.addQueryRegion(-600, -250, 180, 420, "death", [[player]],{}); + + level.defaultZoom = 1300 + game.zoomTransition(level.defaultZoom) spawn.debris(-2250, 1330, 3000, 6); //16 debris per level spawn.debris(-3000, -800, 3280, 6); //16 debris per level spawn.debris(-1400, 410, 2300, 5); //16 debris per level powerUps.spawnStartingPowerUps(25, 500); document.body.style.backgroundColor = "#dcdcde" //"#f2f5f3"; - // game.draw.mapFill = "#444" - // game.draw.bodyFill = "rgba(140,140,140,0.85)" - // game.draw.bodyStroke = "#222" - //foreground - // level.fill.push({ x: -3025, y: 50, width: 4125, height: 1350, color: "rgba(0,0,0,0.05)"}); - // level.fill.push({ x: -1800, y: -500, width: 1975, height: 550, color: "rgba(0,0,0,0.05)"}); - // level.fill.push({ x: -2600, y: -150, width: 700, height: 200, color: "rgba(0,0,0,0.05)"}); //background const BGColor = "rgba(0,0,0,0.1)"; level.fill.push({ @@ -1457,9 +1532,7 @@ const level = { spawn.mapRect(-175, -550, 50, 400); spawn.mapRect(-175, -10, 350, 50); spawn.mapRect(-25, -20, 100, 50); - // spawn.mapRect(-175, -275, 350, 25); - // spawn.mapRect(-175, -250, 25, 75); - // spawn.bodyRect(-170, -175, 14, 160, 1, spawn.propsFriction); //door to starting room + //exit house spawn.mapRect(300, -10, 350, 50); spawn.mapRect(-150, -300, 800, 50); @@ -1506,7 +1579,6 @@ const level = { spawn.bodyRect(-2700, 1150, 100, 160, 1, spawn.propsSlide); //weight spawn.bodyRect(-2550, 1150, 200, 100, 1, spawn.propsSlide); //weight - spawn.bodyRect(-2775, 1300, 400, 100, 1, spawn.propsHoist); //hoist cons[cons.length] = Constraint.create({ pointA: { @@ -1519,7 +1591,6 @@ const level = { }); //blocks - //spawn.bodyRect(-155, -150, 10, 140, 1, spawn.propsFriction); spawn.bodyRect(-165, -150, 30, 35, 1); spawn.bodyRect(-165, -115, 30, 35, 1); spawn.bodyRect(-165, -80, 30, 35, 1); @@ -1527,7 +1598,6 @@ const level = { spawn.bodyRect(-750, 400, 150, 150, 0.5); spawn.bodyRect(-400, 1175, 100, 250, 1); //block to get to top path on bottom level - // spawn.bodyRect(-1450, 737, 75, 103, 0.5); //blocking path spawn.bodyRect(-2525, -50, 145, 100, 0.5); spawn.bodyRect(-2325, -300, 150, 100, 0.5); @@ -1559,9 +1629,6 @@ const level = { spawn.randomBoss(-125, 275, -0.2); spawn.randomBoss(-825, 1000, 0.2); spawn.randomBoss(-1300, -1100, -0.3); - //spawn.randomBoss(600, -1575, 0); - //spawn.randomMob(1120, -1200, 0.3); - //spawn.randomSmallMob(2200, -1775); if (game.difficulty > 3) { if (Math.random() < 0.1) { @@ -1572,12 +1639,16 @@ const level = { } }, office() { + level.custom = () => { + level.playerExitCheck(); + }; + level.defaultZoom = 1400 game.zoomTransition(level.defaultZoom) if (Math.random() < 0.75) { //normal direction start in top left - mech.setPosToSpawn(1375, -1550); //normal spawn + level.setPosToSpawn(1375, -1550); //normal spawn level.exit.x = 3250; level.exit.y = -530; // spawn.randomSmallMob(3550, -550); @@ -1590,7 +1661,7 @@ const level = { }); } else { //reverse direction, start in bottom right - mech.setPosToSpawn(3250, -550); //normal spawn + level.setPosToSpawn(3250, -550); //normal spawn level.exit.x = 1375; level.exit.y = -1530; // spawn.bodyRect(3655, -650, 40, 150); //door @@ -1603,16 +1674,10 @@ const level = { }); } spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 50); //ground bump wall - level.enter.x = mech.spawnPos.x - 50; - level.enter.y = mech.spawnPos.y + 20; + spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); - level.addZone(level.exit.x, level.exit.y, 100, 30, "nextLevel"); - document.body.style.backgroundColor = "#e0e5e0"; - // game.draw.mapFill = "#444" - // game.draw.bodyFill = "rgba(140,140,140,0.85)" - // game.draw.bodyStroke = "#222" // foreground level.fill.push({ @@ -1651,9 +1716,6 @@ const level = { color: "rgba(0,0,0,0.1)" }); - //mech.setPosToSpawn(600, -1200); //normal spawn - //mech.setPosToSpawn(525, -150); //ground first building - //mech.setPosToSpawn(3150, -700); //near exit spawn spawn.debris(-300, -200, 1000, 4); //ground debris //16 debris per level spawn.debris(3500, -200, 800, 4); //ground debris //16 debris per level spawn.debris(-300, -650, 1200, 4); //1st floor debris //16 debris per level @@ -1760,15 +1822,17 @@ const level = { } }, stronghold() { // player made level by Francois 👑 from discord - level.defaultZoom = 1400 + level.custom = () => { + level.playerExitCheck(); + }; - game.zoomTransition(level.defaultZoom) - mech.setPosToSpawn(1900, -10); //normal spawn - level.enter.x = mech.spawnPos.x - 50; - level.enter.y = mech.spawnPos.y - 10; + level.setPosToSpawn(1900, -40); //normal spawn level.exit.x = -350; level.exit.y = -1250; - level.addZone(level.exit.x, level.exit.y, 100, 30, "nextLevel"); + + level.defaultZoom = 1400 + game.zoomTransition(level.defaultZoom) + spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 20); //exit bump spawn.debris(3800, -1480, 300, 12); spawn.debris(3600, -1130, 200, 2); @@ -1992,218 +2056,4 @@ const level = { if (game.difficulty > 3) spawn.randomLevelBoss(1850, -1400, 1); }, - //***************************************************************************************************************** - //***************************************************************************************************************** - //***************************************************************************************************************** - //***************************************************************************************************************** - //***************************************************************************************************************** - //***************************************************************************************************************** - //***************************************************************************************************************** - enter: { - x: 0, - y: 0, - draw() { - ctx.beginPath(); - ctx.moveTo(level.enter.x, level.enter.y + 30); - ctx.lineTo(level.enter.x, level.enter.y - 80); - ctx.bezierCurveTo(level.enter.x, level.enter.y - 170, level.enter.x + 100, level.enter.y - 170, level.enter.x + 100, level.enter.y - 80); - ctx.lineTo(level.enter.x + 100, level.enter.y + 30); - ctx.lineTo(level.enter.x, level.enter.y + 30); - ctx.fillStyle = "#ccc"; - ctx.fill(); - } - }, - exit: { - x: 0, - y: 0, - draw() { - ctx.beginPath(); - ctx.moveTo(level.exit.x, level.exit.y + 30); - ctx.lineTo(level.exit.x, level.exit.y - 80); - ctx.bezierCurveTo(level.exit.x, level.exit.y - 170, level.exit.x + 100, level.exit.y - 170, level.exit.x + 100, level.exit.y - 80); - ctx.lineTo(level.exit.x + 100, level.exit.y + 30); - ctx.lineTo(level.exit.x, level.exit.y + 30); - ctx.fillStyle = "#0ff"; - ctx.fill(); - } - }, - fillBG: [], - drawFillBGs() { - 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() { - 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() { - for (let i = 0, len = level.zones.length; i < len; ++i) { - if ( - player.position.x > level.zones[i].x1 && - player.position.x < level.zones[i].x2 && - player.position.y > level.zones[i].y1 && - player.position.y < level.zones[i].y2 - ) { - level.zoneActions[level.zones[i].action](i); - break; - } - } - }, - addZone(x, y, width, height, action, info) { - level.zones[level.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(i) { - Matter.Body.setVelocity(player, { - x: level.zones[i].info.Vx, - y: level.zones[i].info.Vy - }); - }, - nextLevel() { - //enter when player isn't falling - if (player.velocity.y < 0.1) { - level.levelsCleared++; - level.onLevel++; //cycles map to next level - if (level.onLevel > level.levels.length - 1) level.onLevel = 0; - - level.difficultyIncrease(game.difficultyMode) //increase difficulty based on modes - if (game.isEasyMode && level.levelsCleared % 2) level.difficultyDecrease(1); - game.clearNow = true; //triggers in game.clearMap to remove all physics bodies and setup for new map - } - }, - death() { - mech.death(); - }, - laser(i) { - //draw these in game with spawn.background - mech.damage(level.zones[i].info.dmg); - }, - slow() { - 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() { - 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(x, y, width, height, action, groups = [ - [player], body, mob, powerUp, bullet - ], info) { - level.queryList[level.queryList.length] = { - bounds: { - min: { - x: x, - y: y - }, - max: { - x: x + width, - y: y + height - } - }, - action: action, - groups: groups, - info: info - }; - }, - queryActions: { - bounce(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(target, yVelocity) { - // if (target.velocity.y < 0) { - // mech.undoCrouch(); - // mech.enterAir(); - mech.buttonCD_jump = 0; // reset short jump counter to prevent short jumps on boosts - mech.hardLandCD = 0 // disable hard landing - if (target.velocity.y > 30) { - Matter.Body.setVelocity(target, { - x: target.velocity.x + (Math.random() - 0.5) * 2, - y: -23 //gentle bounce if coming down super fast - }); - } else { - Matter.Body.setVelocity(target, { - x: target.velocity.x + (Math.random() - 0.5) * 2, - y: yVelocity - }); - } - - }, - force(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(target) { - target.force.y -= 0.0011 * target.mass; - }, - death(target) { - target.death(); - } - }, - addToWorld() { - //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 = cat.body; - body[i].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet - 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 = cat.map; - map[i].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet; - 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]); - } - } }; \ No newline at end of file diff --git a/js/mob.js b/js/mob.js index 3e07b52..26e0d09 100644 --- a/js/mob.js +++ b/js/mob.js @@ -1000,12 +1000,14 @@ const mobs = { } } if (Math.random() < mod.isBotSpawner) { - if (Math.random() < 0.33) { + if (Math.random() < 0.25) { b.nailBot(this.position) - } else if (Math.random() < 0.5) { + } else if (Math.random() < 0.33) { b.laserBot(this.position) - } else { + } else if (Math.random() < 0.5) { b.foamBot(this.position) + } else { + b.boomBot(this.position) } // if (mech.energy > 0.33) mech.energy -= 0.33 } diff --git a/js/mods.js b/js/mods.js index 5f597a4..215f20a 100644 --- a/js/mods.js +++ b/js/mods.js @@ -276,23 +276,6 @@ const mod = { mod.throwChargeRate = 1 } }, - { - name: "laser-bot", - description: "a bot defends the space around you
uses a short range laser that drains energy", - maxCount: 9, - count: 0, - allowed() { - return true - }, - requires: "", - effect() { - mod.laserBotCount++; - b.laserBot(); - }, - remove() { - mod.laserBotCount = 0; - } - }, { name: "nail-bot", description: "a bot fires nails at targets in line of sight", @@ -327,13 +310,64 @@ const mod = { mod.foamBotCount = 0; } }, + { + name: "boom-bot", + description: "a bot defends the space around you
ignites an explosion after hitting a mob", + maxCount: 9, + count: 0, + allowed() { + return true + }, + requires: "", + effect() { + mod.boomBotCount++; + b.boomBot(); + }, + remove() { + mod.boomBotCount = 0; + } + }, + { + name: "laser-bot", + description: "a bot defends the space around you
uses a short range laser that drains energy", + maxCount: 9, + count: 0, + allowed() { + return true + }, + requires: "", + effect() { + mod.laserBotCount++; + b.laserBot(); + }, + remove() { + mod.laserBotCount = 0; + } + }, + { + name: "plasma-bot", + description: "a bot uses energy to emit short range plasma
plasma damages and pushes mobs", + maxCount: 1, + count: 0, + allowed() { + return mech.fieldUpgrades[mech.fieldMode].name === "plasma torch" + }, + requires: "plasma torch", + effect() { + mod.plasmaBotCount++; + b.plasmaBot(); + }, + remove() { + mod.plasmaBotCount = 0; + } + }, { name: "scrap bots", description: "12% chance to build a bot after killing a mob
the bot only functions until the end of the level", maxCount: 6, count: 0, allowed() { - return mod.foamBotCount + mod.nailBotCount + mod.laserBotCount > 0 + return mod.foamBotCount + mod.nailBotCount + mod.laserBotCount + mod.boomBotCount + mod.plasmaBotCount > 0 }, requires: "a bot", effect() { @@ -345,19 +379,19 @@ const mod = { }, { name: "bot replication", - description: "duplicate your permanent bots
remove 80% of your ammo", + description: "duplicate your permanent bots
remove 90% of your ammo", maxCount: 1, count: 0, // isNonRefundable: true, allowed() { - return mod.foamBotCount + mod.nailBotCount + mod.laserBotCount > 2 + return mod.foamBotCount + mod.nailBotCount + mod.laserBotCount + mod.boomBotCount + mod.plasmaBotCount > 1 }, - requires: "3 or more bots", + requires: "2 or more bots", effect() { //remove ammo for (let i = 0, len = b.guns.length; i < len; ++i) { if (b.guns[i].ammo != Infinity) { - b.guns[i].ammo = Math.floor(b.guns[i].ammo * 0.2); + b.guns[i].ammo = Math.floor(b.guns[i].ammo * 0.1); } } @@ -374,6 +408,14 @@ const mod = { b.foamBot(); } mod.foamBotCount *= 2 + for (let i = 0; i < mod.boomBotCount; i++) { + b.boomBot(); + } + mod.boomBotCount *= 2 + for (let i = 0; i < mod.plasmaBotCount; i++) { + b.plasmaBot(); + } + mod.plasmaBotCount *= 2 }, remove() {} }, @@ -545,7 +587,7 @@ const mod = { }, { name: "Pauli exclusion", - description: `immune to harm for 1 seconds
activates after being harmed from a collision`, + description: `immune to harm for 1 second
activates after being harmed from a collision`, maxCount: 9, count: 0, allowed() { @@ -1400,7 +1442,7 @@ const mod = { maxCount: 1, count: 0, allowed() { - return mod.haveGunCheck("missiles") || mod.haveGunCheck("flak") || mod.haveGunCheck("grenades") || mod.haveGunCheck("vacuum bomb") || mod.haveGunCheck("pulse") || mod.isMissileField; + return mod.haveGunCheck("missiles") || mod.haveGunCheck("flak") || mod.haveGunCheck("grenades") || mod.haveGunCheck("vacuum bomb") || mod.haveGunCheck("pulse") || mod.isMissileField || mod.isExplodeMob }, requires: "an explosive gun", effect: () => { @@ -2163,6 +2205,8 @@ const mod = { laserBotCount: null, nailBotCount: null, foamBotCount: null, + boomBotCount: null, + plasmaBotCount: null, collisionImmuneCycles: null, blockDmg: null, isPiezo: null, diff --git a/js/player.js b/js/player.js index 67ce6b3..41e2da2 100644 --- a/js/player.js +++ b/js/player.js @@ -94,20 +94,6 @@ const mech = { x: 0, y: 0 }, - setPosToSpawn(xPos, yPos) { - this.spawnPos.x = this.pos.x = xPos; - this.spawnPos.y = this.pos.y = yPos; - this.transX = this.transSmoothX = canvas.width2 - this.pos.x; - this.transY = this.transSmoothY = canvas.height2 - this.pos.y; - this.Vx = this.spawnVel.x; - this.Vy = this.spawnVel.y; - player.force.x = 0; - player.force.y = 0; - Matter.Body.setPosition(player, this.spawnPos); - Matter.Body.setVelocity(player, this.spawnVel); - // mech.transX = -player.position.x - // mech.transY = player.position.y - }, Sy: 0, //adds a smoothing effect to vertical only Vx: 0, Vy: 0, @@ -1507,7 +1493,7 @@ const mech = { } else if ((keys[32] || game.mouseDownRight) && mech.fieldCDcycle < mech.cycle) { //not hold but field button is pressed mech.grabPowerUp(); mech.lookForPickUp(); - const DRAIN = 0.0013 + const DRAIN = 0.0014 if (mech.energy > DRAIN) { mech.energy -= DRAIN; if (mech.energy < 0) { diff --git a/todo.txt b/todo.txt index e09fbb8..3491c58 100644 --- a/todo.txt +++ b/todo.txt @@ -1,10 +1,21 @@ -rerolls drop 60% more often -mines delay a 1/2 second longer before they arm -mod: supply chain - doubles your current ammo, requires mod:logistics -mod: neocognitron - pulse auto aiming +mod - boomBot: explodes on mobs in close range +mod - plasma-bot: bot that fires your plasma torch +(limit 1 bot) (requires plasma torch) +(you can get 2 plasma-bots with bot replication) +(you can switch to a new field after getting plasma-bot) + ************** TODO - n-gon ************** +mob that flashes the player (makes the graphics not update for a couple seconds) + +held blocks aren't moving to the next level + only issue is setting held block to not collide + +mod do 50% more damage in close, but 50% less at a distance + code it like mod.isFarAwayDmg + have these mods disable each other + phase field still isn't fun rework renormalization mod as well does phase field need the stealth flag? @@ -12,9 +23,6 @@ phase field still isn't fun mod: use the stealth flag from the phase decoherence field maybe trigger it along with the damage immunity CD -levels: make a function in the main game loop that runs level specific code - reset the level function as each new level loads - mod: efficient shielding (requires standing wave harmonics field) lowers force applied when blocking mobs (instead of flinging them away, you push them like with plasma torch), but uses less energy to block mobs and making it so liquid nitrogen and uranium reactor core have that effect in a radius around the player instead of on contact @@ -23,9 +31,6 @@ mod: efficient shielding (requires standing wave harmonics field) mod harmonic shield: slow everything in range around shield (temporal shield) set max speed? -need a mod that effects ice status - mod: ice status effect lasts twice as long - mod: bot very slowly follows you and gives you a bonus when it's in range it moves through walls effect: damage bonus?, damage reduction?, push away mobs, limit top speed of mobs/blocks/player?