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 let composite = [] //rotors and other map elements that don't fit const level = { defaultZoom: 1400, onLevel: -1, levelsCleared: 0, //see level.populateLevels: (intro, ... , reservoir, reactor, ... , gauntlet, final) added later playableLevels: ["labs", "rooftops", "skyscrapers", "warehouse", "highrise", "office", "aerie", "satellite", "sewers", "testChamber", "pavilion"], communityLevels: ["stronghold", "basement", "crossfire", "vats", "run", "n-gon", "house", "perplex", "coliseum", "tunnel"], trainingLevels: ["walk", "crouch", "jump", "hold", "throw", "throwAt", "deflect", "heal", "fire", "nailGun", "shotGun", "superBall", "matterWave", "missile", "stack", "mine", "grenades", "harpoon"], levels: [], start() { if (level.levelsCleared === 0) { //this code only runs on the first level // simulation.isHorizontalFlipped = true // m.setField("metamaterial cloaking") // b.giveGuns("harpoon") // tech.giveTech("grappling hook") // tech.giveTech("bulk modulus") // for (let i = 0; i < 2; i++) powerUps.directSpawn(0, 0, "tech"); // for (let i = 0; i < 9; i++) tech.giveTech("dynamo-bot") // for (let i = 10; i < tech.tech.length; i++) { tech.tech[i].isBanished = true } // powerUps.research.changeRerolls(100000) // for (let i = 0; i < 2; i++) tech.giveTech("undefined") // tech.tech[297].frequency = 100 // m.setField("plasma torch") // tech.giveTech("plasma ball") // m.immuneCycle = Infinity //you can't take damage // level.difficultyIncrease(30) //30 is near max on hard //60 is near max on why // simulation.enableConstructMode() //used to build maps in testing mode // level.reactor(); // level.pavilion(); //not in rotation, used for testing if (simulation.isTraining) { level.walk(); } else { level.intro(); } //normal starting level ************************************************ // powerUps.research.changeRerolls(3000) // for (let i = 0; i < 30; i++) powerUps.spawn(player.position.x + Math.random() * 50, player.position.y - Math.random() * 50, "tech", false); // for (let i = 0; i < 3; i++) tech.giveTech("undefined") // lore.techCount = 3 // simulation.isCheating = false //true; // localSettings.loreCount = 0; //this sets what conversation is heard // if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage // level.onLevel = -1 //this sets level.levels[level.onLevel] = undefined which is required to run the conversation // level.null() // lore.unlockTesting(); // tech.giveTech("tinker"); //show junk tech in experiment mode } else { spawn.setSpawnList(); //picks a couple mobs types for a themed random mob spawns // spawn.pickList = ["focuser", "focuser"] level[level.levels[level.onLevel]](); //picks the current map from the the levels array if (!simulation.isCheating && !build.isExperimentRun && !simulation.isTraining) { localSettings.runCount += level.levelsCleared //track the number of total runs locally localSettings.levelsClearedLastGame = level.levelsCleared if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage } } if (!simulation.isTraining) level.levelAnnounce(); simulation.noCameraScroll(); simulation.setZoom(); level.addToWorld(); //add bodies to game engine simulation.draw.setPaths(); b.respawnBots(); m.resetHistory(); if (tech.isForeverDrones) { if (tech.isDroneRadioactive) { for (let i = 0; i < tech.isForeverDrones * 0.25; i++) { b.droneRadioactive({ x: m.pos.x + 30 * (Math.random() - 0.5), y: m.pos.y + 30 * (Math.random() - 0.5) }, 5) bullet[bullet.length - 1].endCycle = Infinity } } else { for (let i = 0; i < tech.isForeverDrones; i++) { b.drone({ x: m.pos.x + 30 * (Math.random() - 0.5), y: m.pos.y + 30 * (Math.random() - 0.5) }, 5) bullet[bullet.length - 1].endCycle = Infinity } } } if (tech.isExtraMaxEnergy) { tech.healMaxEnergyBonus += 0.05 * powerUps.totalPowerUps //Math.min(0.02 * powerUps.totalPowerUps, 0.51) m.setMaxEnergy(); } if (tech.isGunCycle) { b.inventoryGun++; if (b.inventoryGun > b.inventory.length - 1) b.inventoryGun = 0; simulation.switchGun(); } if (tech.isSwitchReality && powerUps.research.count > 0) { powerUps.research.changeRerolls(-1); simulation.makeTextLog(`simulation.amplitude = ${Math.random()}`); m.switchWorlds() simulation.trails() powerUps.spawn(player.position.x + Math.random() * 50, player.position.y - Math.random() * 50, "tech", false); } if (tech.isHealLowHealth) { const len = Math.ceil((m.maxHealth - m.health) / 0.26) for (let i = 0; i < len; i++) powerUps.spawn(player.position.x + 90 * (Math.random() - 0.5), player.position.y + 90 * (Math.random() - 0.5), "heal", false); } if (tech.isMACHO) spawn.MACHO() for (let i = 0; i < tech.wimpCount; i++) { spawn.WIMP() for (let j = 0, len = 5; j < len; j++) powerUps.spawn(level.exit.x + 100 * (Math.random() - 0.5), level.exit.y - 100 + 100 * (Math.random() - 0.5), "research", false) } for (let i = 0; i < tech.wimpExperiment; i++) spawn.WIMP() // if (tech.isFlipFlopLevelReset && !tech.isFlipFlopOn) { if ((tech.isRelay || tech.isFlipFlop) && !tech.isFlipFlopOn) { tech.isFlipFlopOn = true m.eyeFillColor = m.fieldMeterColor simulation.makeTextLog(`tech.isFlipFlopOn = true`); } if (tech.isSpawnExitTech) { for (let i = 0; i < 2; i++) powerUps.spawn(level.exit.x + 10 * (Math.random() - 0.5), level.exit.y - 100 + 10 * (Math.random() - 0.5), "tech", false) //exit // for (let i = 0; i < 2; i++) powerUps.spawn(player.position.x + 90 * (Math.random() - 0.5), player.position.y + 90 * (Math.random() - 0.5), "tech", false); //start } if (m.plasmaBall) { m.plasmaBall.isOn = false } }, trainingText(say) { simulation.lastLogTime = 0; //clear previous messages simulation.isTextLogOpen = true simulation.makeTextLog(`supervised.learning(${(Date.now()/1000).toFixed(0)} s):
${say}
`, Infinity) simulation.isTextLogOpen = false // lore.trainer.text("Wow. Just a platform.") }, trainingBackgroundColor: "#e1e1e1", custom() {}, customTopLayer() {}, setDifficulty() { simulation.difficulty = 0 m.dmgScale = 1; //damage done by player decreases each level simulation.accelScale = 1 //mob acceleration increases each level simulation.CDScale = 1 //mob CD time decreases each level simulation.dmgScale = Math.max(0.1, 0.34 * simulation.difficulty) //damage done by mobs scales with total levels simulation.healScale = 1 / (1 + simulation.difficulty * 0.052) //a higher denominator makes for lower heals // m.health += heal * simulation.healScale; }, difficultyIncrease(num = 1) { for (let i = 0; i < num; i++) { simulation.difficulty++ m.dmgScale *= 0.925; //damage done by player decreases each level if (simulation.accelScale < 6) simulation.accelScale *= 1.025 //mob acceleration increases each level if (simulation.CDScale > 0.15) simulation.CDScale *= 0.965 //mob CD time decreases each level } simulation.dmgScale = Math.max(0.1, 0.34 * simulation.difficulty) //damage done by mobs scales with total levels simulation.healScale = 1 / (1 + simulation.difficulty * 0.052) //a higher denominator makes for lower heals // m.health += heal * simulation.healScale; // console.log(`CD = ${simulation.CDScale}`) }, difficultyDecrease(num = 1) { //used in easy mode for simulation.reset() for (let i = 0; i < num; i++) { simulation.difficulty-- m.dmgScale /= 0.925; //damage done by player decreases each level if (simulation.accelScale > 1) simulation.accelScale /= 1.025 //mob acceleration increases each level if (simulation.CDScale < 1) simulation.CDScale /= 0.965 //mob CD time decreases each level } if (simulation.difficulty < 1) simulation.difficulty = 0; simulation.dmgScale = Math.max(0.1, 0.34 * simulation.difficulty) //damage done by mobs scales with total levels simulation.healScale = 1 / (1 + simulation.difficulty * 0.052) }, difficultyText() { if (simulation.difficultyMode === 1) { return "easy" } else if (simulation.difficultyMode === 2) { return "normal" } else if (simulation.difficultyMode === 4) { return "hard" } else if (simulation.difficultyMode === 6) { return "why" } }, levelAnnounce() { const difficulty = simulation.isCheating ? "testing" : level.difficultyText() if (level.levelsCleared === 0) { document.title = "n-gon: (" + difficulty + ")"; } else { document.title = `n-gon: ${level.levelsCleared} ${level.levels[level.onLevel]} (${difficulty})` simulation.makeTextLog(`level.onLevel = "${level.levels[level.onLevel]}"`); } // simulation.makeTextLog(` // input.key.up = ["${input.key.up}", "ArrowUp"] //
input.key.left = ["${input.key.left}", "ArrowLeft"] //
input.key.down = ["${input.key.down}", "ArrowDown"] //
input.key.right = ["${input.key.right}", "ArrowRight"] //
//
m.fieldMode = "${m.fieldUpgrades[m.fieldMode].name}" //
input.key.field = ["${input.key.field}", "right mouse"] //
m.field.description = "${m.fieldUpgrades[m.fieldMode].description}" // `, 1200); }, disableExit: false, nextLevel() { if (!level.disableExit) { level.levelsCleared++; level.onLevel++; //cycles map to next level if (simulation.isTraining) { if (level.onLevel > level.levels.length - 1) { level.disableExit = true document.getElementById("health").style.display = "none" document.getElementById("health-bg").style.display = "none" document.getElementById("text-log").style.opacity = 0; //fade out any active text logs document.getElementById("fade-out").style.opacity = 1; //slowly fades out setTimeout(function() { simulation.paused = true; level.disableExit = false; engine.world.bodies.forEach((body) => { Matter.Composite.remove(engine.world, body) }) Engine.clear(engine); simulation.splashReturn(); }, 6000); return } else { level.setDifficulty() } } else { if (level.onLevel > level.levels.length - 1) level.onLevel = 0; level.difficultyIncrease(simulation.difficultyMode) } //reset lost tech display for (let i = 0; i < tech.tech.length; i++) { if (tech.tech[i].isLost) tech.tech[i].isLost = false; } tech.isDeathAvoidedThisLevel = false; simulation.updateTechHUD(); simulation.clearNow = true; //triggers in simulation.clearMap to remove all physics bodies and setup for new map } }, populateLevels() { //run a second time if URL is loaded if (document.getElementById("seed").value) { Math.initialSeed = String(document.getElementById("seed").value) Math.seed = Math.abs(Math.hash(Math.initialSeed)) //update randomizer seed in case the player changed it } if (simulation.isTraining) { level.levels = level.trainingLevels.slice(0) //copy array, not by just by assignment } else { simulation.isHorizontalFlipped = (Math.seededRandom() < 0.5) ? true : false //if true, some maps are flipped horizontally level.levels = level.playableLevels.slice(0) //copy array, not by just by assignment if (simulation.isCommunityMaps) { // level.levels.push(level.communityLevels) level.levels = level.levels.concat(level.communityLevels) level.levels = shuffle(level.levels); //shuffles order of maps level.levels.splice(0, 9); //remove some random levels to make up for adding the community levels simulation.isHorizontalFlipped = false; } else { level.levels = shuffle(level.levels); //shuffles order of maps } // level.levels.splice(Math.floor(level.levels.length * (0.4 + 0.6 * Math.random())), 0, "reservoir"); //add level to the back half of the randomized levels list level.levels.splice(Math.floor(Math.seededRandom((level.levels.length) * 0.4, level.levels.length)), 0, "reservoir"); //add level to the back half of the randomized levels list level.levels.splice(Math.floor(Math.seededRandom((level.levels.length) * 0.4, level.levels.length)), 0, "reactor"); //add level to the back half of the randomized levels list level.levels.splice(0, 2); //remove 2 levels from the start of the array if (!build.isExperimentSelection || (build.hasExperimentalMode && !simulation.isCheating)) { //experimental mode is endless, unless you only have an experiment Tech level.levels.unshift("intro"); //add level to the start of the randomized levels list level.levels.push("gauntlet"); //add level to the end of the randomized levels list level.levels.push("final"); //add level to the end of the randomized levels list } } //set seeded random lists of mobs and bosses spawn.mobTypeSpawnOrder = [] for (let i = 0; i < level.levels.length; i++) spawn.mobTypeSpawnOrder.push(spawn.fullPickList[Math.floor(Math.seededRandom(0, spawn.fullPickList.length))]) spawn.bossTypeSpawnOrder = [] for (let i = 0; i < level.levels.length * 2; i++) spawn.bossTypeSpawnOrder.push(spawn.randomBossList[Math.floor(Math.seededRandom(0, spawn.randomBossList.length))]) }, flipHorizontal() { const flipX = (who) => { for (let i = 0, len = who.length; i < len; i++) { Matter.Body.setPosition(who[i], { x: -who[i].position.x, y: who[i].position.y }) } } flipX(map) flipX(body) flipX(mob) flipX(powerUp) for (let i = 0, len = cons.length; i < len; i++) { cons[i].pointA.x *= -1 cons[i].pointB.x *= -1 } for (let i = 0, len = consBB.length; i < len; i++) { consBB[i].pointA.x *= -1 consBB[i].pointB.x *= -1 } level.exit.x = -level.exit.x - 100 //minus the 100 because of the width of the graphic }, exitCount: 0, // 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.exitCount++ // if (level.exitCount > 120) { // level.exitCount = 0 // level.nextLevel() // } // } // }, setPosToSpawn(xPos, yPos) { m.spawnPos.x = m.pos.x = xPos; m.spawnPos.y = m.pos.y = yPos; level.enter.x = m.spawnPos.x - 50; level.enter.y = m.spawnPos.y + 20; m.transX = m.transSmoothX = canvas.width2 - m.pos.x; m.transY = m.transSmoothY = canvas.height2 - m.pos.y; m.Vx = m.spawnVel.x; m.Vy = m.spawnVel.y; player.force.x = 0; player.force.y = 0; Matter.Body.setPosition(player, m.spawnPos); Matter.Body.setVelocity(player, m.spawnVel); //makes perfect diamagnetism tech: Lenz's law show up in the right spot at the start of a level m.fieldPosition = { x: m.pos.x, y: m.pos.y } m.fieldAngle = m.angle }, 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, drawAndCheck() { if ( //check 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 - 0 && player.velocity.y < 0.15 ) { level.exitCount += input.down ? 8 : 2 } else if (level.exitCount > 0) { level.exitCount -= 2 } 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(); if (level.exitCount > 0) { //stroke outline of door from 2 sides, grows with count ctx.beginPath(); ctx.moveTo(level.exit.x, level.exit.y + 40); ctx.lineTo(level.exit.x, level.exit.y - 80); ctx.bezierCurveTo(level.exit.x, level.exit.y - 148, level.exit.x + 50, level.exit.y - 148, level.exit.x + 50, level.exit.y - 148); ctx.moveTo(level.exit.x + 100, level.exit.y + 40); ctx.lineTo(level.exit.x + 100, level.exit.y - 80); ctx.bezierCurveTo(level.exit.x + 100, level.exit.y - 148, level.exit.x + 50, level.exit.y - 148, level.exit.x + 50, level.exit.y - 148); ctx.setLineDash([200, 200]); ctx.lineDashOffset = Math.max(-15, 185 - 2.1 * level.exitCount) ctx.strokeStyle = "#444" ctx.lineWidth = 2 ctx.stroke(); ctx.setLineDash([0, 0]); if (level.exitCount > 100) { level.exitCount = 0 level.nextLevel() } } }, // 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(); // } }, addToWorld() { //needs to be run to put bodies into the world for (let i = 0; i < body.length; i++) { if (body[i] !== m.holdingTarget && !body[i].isNoSetCollision) { 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"; Composite.add(engine.world, body[i]); //add to world } for (let i = 0; i < map.length; i++) { 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 Composite.add(engine.world, map[i]); //add to world } }, spinner(x, y, width, height, density = 0.001, angle = 0, frictionAir = 0.001, angularVelocity = 0) { x += width / 2 y += height / 2 const who = body[body.length] = Bodies.rectangle(x, y, width, height, { collisionFilter: { category: cat.map, mask: cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet }, isNoSetCollision: true, isNotHoldable: true, frictionAir: frictionAir, friction: 1, frictionStatic: 1, restitution: 0, }); Matter.Body.setAngle(who, angle) Matter.Body.setAngularVelocity(who, angularVelocity); Matter.Body.setDensity(who, density) const constraint = Constraint.create({ //fix rotor in place, but allow rotation pointA: { x: who.position.x, y: who.position.y }, bodyB: who, stiffness: 1, damping: 1 }); Composite.add(engine.world, constraint); return constraint }, boost(x, y, height = 1000) { //height is how high the player will be flung above y who = map[map.length] = Matter.Bodies.fromVertices(x + 50, y + 35, Vertices.fromPath("120 40 -120 40 -50 -40 50 -40"), { collisionFilter: { category: cat.body, mask: cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet //cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet }, boostBounds: { min: { x: x, y: y - 20 }, max: { x: x + 100, y: y } }, yVelocity: -1.21 * Math.sqrt(Math.abs(height)), query() { // check for collisions query = (who) => { if (Matter.Query.region(who, this.boostBounds).length > 0) { list = Matter.Query.region(who, this.boostBounds) Matter.Body.setVelocity(list[0], { x: list[0].velocity.x + (Math.random() - 0.5) * 2.5, //add a bit of horizontal drift to reduce endless bounces y: this.yVelocity //give a upwards velocity }); } } query(body) query(mob) query(bullet) query(powerUp) //player collision if (Matter.Query.region([player], this.boostBounds).length > 0) { m.buttonCD_jump = 0; // reset short jump counter to prevent short jumps on boosts m.hardLandCD = 0 // disable hard landing if (player.velocity.y > 26) { Matter.Body.setVelocity(player, { x: player.velocity.x, y: -15 //gentle bounce if coming down super fast }); } else { Matter.Body.setVelocity(player, { x: player.velocity.x + (Math.random() - 0.5) * 2.5, y: this.yVelocity //give a upwards velocity that will put the player that the height desired }); } } //draw ctx.fillStyle = "rgba(200,0,255,0.15)"; ctx.fillRect(this.boostBounds.min.x, this.boostBounds.min.y - 10, 100, 30); ctx.fillStyle = "rgba(200,0,255,0.05)"; ctx.fillRect(this.boostBounds.min.x, this.boostBounds.min.y - 50, 100, 70); // ctx.fillStyle = "rgba(200,0,255,0.02)"; // ctx.fillRect(x, y - 120, 100, 120); }, }); return who }, elevator(x, y, width, height, maxHeight, force = 0.003, friction = { up: 0.01, down: 0.2 }, isAtTop = false) { x += width / 2 y += height / 2 maxHeight += height / 2 const yTravel = maxHeight - y force += simulation.g const who = body[body.length] = Bodies.rectangle(x, isAtTop ? maxHeight : y, width, height, { collisionFilter: { category: cat.map, mask: cat.map | cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet }, isNoSetCollision: true, inertia: Infinity, //prevents rotation isNotHoldable: true, friction: 1, frictionStatic: 1, restitution: 0, frictionAir: 0.001, holdX: x, move() { if (!m.isBodiesAsleep) { if (this.isUp) { //moving up still with high air friction this.force.y -= force * this.mass //hard force propels up, even with high friction if (this.position.y < maxHeight) { //switch to down mode this.isUp = false this.frictionAir = friction.down //adds a hard jerk at the top of vertical motion because it's fun Matter.Body.setPosition(this, { x: this.holdX, y: maxHeight }); Matter.Body.setVelocity(this, { x: 0, y: 0 }); } } else if (this.position.y + 10 * this.velocity.y > y) { //free falling down, with only air friction Matter.Body.setVelocity(this, { //slow down early to avoid a jerky stop that can pass through blocks x: 0, y: this.velocity.y * 0.7 }); if (this.position.y + this.velocity.y > y) { //switch to up mode this.isUp = true this.frictionAir = friction.up } } } // hold horizontal position Matter.Body.setPosition(this, { x: this.holdX, y: this.position.y }); Matter.Body.setVelocity(this, { x: 0, y: this.velocity.y }); }, off() { Matter.Body.setPosition(this, { x: this.holdX, y: this.position.y }); Matter.Body.setVelocity(this, { x: 0, y: this.velocity.y }); }, constraint: this.null, addConstraint() { this.constraint = Constraint.create({ pointA: { x: this.position.x, y: this.position.y }, bodyB: this, stiffness: 0.01, damping: 0.3 }); Composite.add(engine.world, this.constraint); }, removeConstraint() { Composite.remove(engine.world, this.constraint, true) }, drawTrack() { ctx.fillStyle = "#ccc" ctx.fillRect(this.holdX, y, 5, yTravel) } }); Matter.Body.setDensity(who, 0.01) //10x density for added stability return who }, spring(x, y, v = "-100 0 100 0 70 40 0 50 -70 40", force = 0.01, distance = 300, angle = 0) { const who = body[body.length] = Matter.Bodies.fromVertices(x, y, Vertices.fromPath(v), { collisionFilter: { category: cat.body, mask: cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet //cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet }, inertia: Infinity, //prevents rotation isNotHoldable: true, friction: 1, frictionStatic: 1, restitution: 0, frictionAir: 1, density: 0.1, isReady: true, isResetting: false, query() { if (this.isReady) { if (Matter.Query.collides(this, [player]).length) { this.isReady = false this.constraint.stiffness = 0 this.constraint.damping = 0 //0.3 this.frictionAir = 0 Matter.Body.setVelocity(this, { x: 0, y: 0 }); //show graphically being ready? } } else { if (this.isResetting) { this.constraint.stiffness += 0.0005 if (this.constraint.stiffness > 0.1) { this.isResetting = false this.isReady = true } } else { if (Vector.magnitudeSquared(Vector.sub(this.position, { x: x, y: y })) < distance * distance) { this.force.y -= force * this.mass } else { this.constraint.damping = 1 this.frictionAir = 1 this.isResetting = true Matter.Body.setVelocity(this, { x: 0, y: 0 }); } } } } }); who.constraint = Constraint.create({ pointA: { x: who.position.x, y: who.position.y }, bodyB: who, stiffness: 1, damping: 1 }); Composite.add(engine.world, who.constraint); return who }, rotor(x, y, rotate = 0, radius = 800, width = 40, density = 0.0005) { const rotor1 = Matter.Bodies.rectangle(x, y, width, radius, { density: density, isNotHoldable: true, isNonStick: true, collisionFilter: { category: cat.map, mask: cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet }, isNoSetCollision: true, }); const rotor2 = Matter.Bodies.rectangle(x, y, width, radius, { angle: Math.PI / 2, density: density, isNotHoldable: true, isNonStick: true, collisionFilter: { category: cat.map, mask: cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet }, isNoSetCollision: true, }); rotor = Body.create({ //combine rotor1 and rotor2 parts: [rotor1, rotor2], restitution: 0, collisionFilter: { category: cat.map, mask: cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet }, isNoSetCollision: true, }); Matter.Body.setPosition(rotor, { x: x, y: y }); Composite.add(engine.world, [rotor]); body[body.length] = rotor1 body[body.length] = rotor2 // setTimeout(function() { // rotor.collisionFilter.category = cat.body; // rotor.collisionFilter.mask = cat.body | cat.player | cat.bullet | cat.mob | cat.mobBullet //| cat.map // }, 1000); const constraint = Constraint.create({ //fix rotor in place, but allow rotation pointA: { x: x, y: y }, bodyB: rotor }); Composite.add(engine.world, constraint); if (rotate) { rotor.rotate = function() { if (!m.isBodiesAsleep) { Matter.Body.applyForce(rotor, { x: rotor.position.x + 100, y: rotor.position.y + 100 }, { x: rotate * rotor.mass, y: 0 }) } else { Matter.Body.setAngularVelocity(rotor, 0); } } } composite[composite.length] = rotor return rotor }, toggle(x, y, isOn = false, isLockOn = false) { spawn.mapVertex(x + 65, y + 2, "70 10 -70 10 -40 -10 40 -10"); //toggle platform map[map.length - 1].restitution = 0; map[map.length - 1].friction = 1; map[map.length - 1].frictionStatic = 1; spawn.bodyRect(x, y - 5, 120, 15) //toggle body called flip let flip = body[body.length - 1]; flip.isNoSetCollision = true //prevents collision from being rewritten in level.addToWorld flip.collisionFilter.category = cat.body flip.collisionFilter.mask = cat.player | cat.body flip.isNotHoldable = true flip.frictionAir = 0.01 flip.restitution = 0 Matter.Body.setDensity(flip, 0.003) if (isOn) { Matter.Body.setAngle(flip, (0.25 - 0.5) * Math.PI) } else { Matter.Body.setAngle(flip, (-0.25 - 0.5) * Math.PI) } cons[cons.length] = Constraint.create({ pointA: { x: x + 65, y: y - 5 }, bodyB: flip, stiffness: 1, length: 0 }); Composite.add(engine.world, [cons[cons.length - 1]]); return { flip: flip, isOn: isOn, query() { const limit = { right: (-0.25 - 0.5) * Math.PI, left: (0.25 - 0.5) * Math.PI } if (flip.angle < limit.right) { Matter.Body.setAngle(flip, limit.right) Matter.Body.setAngularVelocity(flip, 0); if (!isLockOn) this.isOn = false } else if (flip.angle > limit.left) { Matter.Body.setAngle(flip, limit.left) Matter.Body.setAngularVelocity(flip, 0); this.isOn = true } if (this.isOn) { ctx.beginPath(); ctx.moveTo(flip.vertices[0].x, flip.vertices[0].y); for (let j = 1; j < flip.vertices.length; j++) { ctx.lineTo(flip.vertices[j].x, flip.vertices[j].y); } ctx.lineTo(flip.vertices[0].x, flip.vertices[0].y); ctx.fillStyle = "#3df" ctx.fill(); ctx.lineWidth = 1; ctx.strokeStyle = color.blockS; ctx.stroke(); } }, } }, button(x, y, width = 126) { spawn.mapVertex(x + 65, y + 2, "100 10 -100 10 -70 -10 70 -10"); map[map.length - 1].restitution = 0; map[map.length - 1].friction = 1; map[map.length - 1].frictionStatic = 1; // const buttonSensor = Bodies.rectangle(x + 35, y - 1, 70, 20, { // isSensor: true // }); return { isUp: false, min: { x: x + 2, y: y - 11 }, max: { x: x + width, y: y - 10 }, width: width, height: 20, query() { if (Matter.Query.region(body, this).length === 0 && Matter.Query.region([player], this).length === 0) { this.isUp = true; } else { if (this.isUp === true) { const list = Matter.Query.region(body, this) //are any blocks colliding with this if (list.length > 0) { if (list[0].bounds.max.x - list[0].bounds.min.x < 150 && list[0].bounds.max.y - list[0].bounds.min.y < 150) { //not too big of a block Matter.Body.setPosition(list[0], { //teleport block to the center of the button x: this.min.x + width / 2, y: list[0].position.y }) } Matter.Body.setVelocity(list[0], { x: 0, y: 0 }); } } this.isUp = false; } }, draw() { ctx.fillStyle = "hsl(0, 100%, 70%)" if (this.isUp) { ctx.fillRect(this.min.x, this.min.y - 10, this.width, 20) } else { ctx.fillRect(this.min.x, this.min.y - 3, this.width, 25) } } } }, vanish(x, y, width, height, isVertical = false, hide = { x: 0, y: 150 }) { x = x + width / 2 y = y + height / 2 const vertices = [{ x: x, y: y, index: 0, isInternal: false }, { x: x + width, y: y, index: 1, isInternal: false }, { x: x + width, y: y + height, index: 4, isInternal: false }, { x: x, y: y + height, index: 3, isInternal: false }] const block = body[body.length] = Bodies.fromVertices(x, y, vertices, { // const block = body[body.length] = Bodies.rectangle(x, y, width, height, { collisionFilter: { category: cat.map, mask: cat.player | cat.body | cat.bullet | cat.powerUp // | cat.mob | cat.mobBullet }, isNoSetCollision: true, inertia: Infinity, //prevents rotation isNotHoldable: true, isNonStick: true, //this keep sporangium from sticking isTouched: false, fadeTime: 10 + Math.ceil(0.25 * width), fadeCount: null, isThere: true, returnTime: 120, returnCount: 0, shrinkVertices(size) { if (isVertical) { return [{ x: x, y: y * size, index: 0, isInternal: false }, { x: x + width, y: y * size, index: 1, isInternal: false }, { x: x + width, y: (y + height) * size, index: 4, isInternal: false }, { x: x, y: (y + height) * size, index: 3, isInternal: false }] } else { return [{ x: x * size, y: y, index: 0, isInternal: false }, { x: (x + width) * size, y: y, index: 1, isInternal: false }, { x: (x + width) * size, y: y + height, index: 4, isInternal: false }, { x: x * size, y: y + height, index: 3, isInternal: false }] } }, query() { if (this.isThere) { if (this.isTouched) { if (!m.isBodiesAsleep) { this.fadeCount-- Matter.Body.setVertices(this, this.shrinkVertices(Math.max(this.fadeCount / this.fadeTime, 0.03))) //take on harpoon shape } if (this.fadeCount < 1) { Matter.Body.setPosition(this, hide) this.isThere = false this.isTouched = false this.collisionFilter.mask = 0 //cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet this.returnCount = this.returnTime Matter.Body.setVertices(this, this.shrinkVertices(1)) //take on harpoon shape Matter.Body.setVertices(this, vertices) //take on harpoon shape } } else if (Matter.Query.collides(this, [player]).length) { // || (Matter.Query.collides(this, body).length)) { this.isTouched = true this.fadeCount = this.fadeTime; } } else { if (!m.isBodiesAsleep) { this.returnCount-- if (this.returnCount < 1) { Matter.Body.setPosition(this, { x: x, y: y }) if (Matter.Query.collides(this, [player]).length) { //|| (Matter.Query.collides(this, body).length)) { Matter.Body.setPosition(this, hide) this.returnCount = 15 } else { this.isThere = true this.collisionFilter.mask = cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet this.fadeCount = this.fadeTime //delete any overlapping blocks const blocks = Matter.Query.collides(this, body) for (let i = 0; i < blocks.length; i++) { if (blocks[i].bodyB !== this && blocks[i].bodyB !== m.holdingTarget) { //dont' delete yourself <----- bug here maybe... Matter.Composite.remove(engine.world, blocks[i].bodyB); blocks[i].bodyB.isRemoveMeNow = true for (let i = 1; i < body.length; i++) { //find which index in body array it is and remove from array if (body[i].isRemoveMeNow) { body.splice(i, 1); break } } } } } } } } ctx.beginPath(); const v = this.vertices; ctx.moveTo(v[0].x, v[0].y); for (let i = 1; i < v.length; ++i) ctx.lineTo(v[i].x, v[i].y); ctx.lineTo(v[0].x, v[0].y); ctx.fillStyle = "#586370" ctx.fill(); // const color = 220 * (1 - this.fadeCount / this.fadeTime) // ctx.fillStyle = `rgb(${color},220, 200)` // ctx.fillStyle = `rgba(0,220,200,${this.fadeCount/this.fadeTime+0.05})` // ctx.strokeStyle = `#bff` // ctx.stroke(); }, }); Matter.Body.setStatic(block, true); //make static // Composite.add(engine.world, block); //add to world if (simulation.isHorizontalFlipped) x *= -1 return block }, door(x, y, width, height, distance, speed = 1) { x = x + width / 2 y = y + height / 2 const doorBlock = body[body.length] = Bodies.rectangle(x, y, width, height, { collisionFilter: { category: cat.map, mask: cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet //cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet }, isNoSetCollision: true, inertia: Infinity, //prevents rotation isNotHoldable: true, friction: 1, frictionStatic: 1, restitution: 0, isClosing: false, openClose() { if (!m.isBodiesAsleep) { if (this.isClosing) { if (this.position.y < y) { //try to close if ( Matter.Query.collides(this, [player]).length === 0 && Matter.Query.collides(this, body).length < 2 && Matter.Query.collides(this, mob).length === 0 ) { const position = { x: this.position.x, y: this.position.y + speed } Matter.Body.setPosition(this, position) } } } else { if (this.position.y > y - distance) { //try to open const position = { x: this.position.x, y: this.position.y - speed } Matter.Body.setPosition(this, position) } } } }, draw() { ctx.fillStyle = "#555" ctx.beginPath(); const v = this.vertices; ctx.moveTo(v[0].x, v[0].y); for (let i = 1; i < v.length; ++i) { ctx.lineTo(v[i].x, v[i].y); } ctx.lineTo(v[0].x, v[0].y); ctx.fill(); } }); Matter.Body.setStatic(doorBlock, true); //make static return doorBlock }, portal(centerA, angleA, centerB, angleB) { const width = 50 const height = 150 const mapWidth = 200 const unitA = Matter.Vector.rotate({ x: 1, y: 0 }, angleA) const unitB = Matter.Vector.rotate({ x: 1, y: 0 }, angleB) draw = function() { ctx.beginPath(); //portal let v = this.vertices; ctx.moveTo(v[0].x, v[0].y); for (let i = 1; i < v.length; ++i) { ctx.lineTo(v[i].x, v[i].y); } ctx.fillStyle = this.color ctx.fill(); } query = function(isRemoveBlocks = false) { if (Matter.Query.collides(this, [player]).length === 0) { //not touching player if (player.isInPortal === this) player.isInPortal = null } else if (player.isInPortal !== this) { //touching player if (m.buttonCD_jump === m.cycle) player.force.y = 0 // undo a jump right before entering the portal m.buttonCD_jump = 0 //disable short jumps when letting go of jump key player.isInPortal = this.portalPair //teleport if (this.portalPair.angle % (Math.PI / 2)) { //if left, right up or down if (m.immuneCycle < m.cycle + tech.collisionImmuneCycles) m.immuneCycle = m.cycle + tech.collisionImmuneCycles; //player is immune to damage for 30 cycles Matter.Body.setPosition(player, this.portalPair.portal.position); } else { //if at some odd angle if (m.immuneCycle < m.cycle + tech.collisionImmuneCycles) m.immuneCycle = m.cycle + tech.collisionImmuneCycles; //player is immune to damage for 30 cycles Matter.Body.setPosition(player, this.portalPair.position); } //rotate velocity let mag if (this.portalPair.angle !== 0 && this.portalPair.angle !== Math.PI) { //portal that fires the player up mag = Math.max(10, Math.min(50, player.velocity.y * 0.8)) + 11 } else { mag = Math.max(6, Math.min(50, Vector.magnitude(player.velocity))) } let v = Vector.mult(this.portalPair.unit, mag) Matter.Body.setVelocity(player, v); // move bots to player for (let i = 0; i < bullet.length; i++) { if (bullet[i].botType) { // Matter.Body.setPosition(bullet[i], this.portalPair.portal.position); Matter.Body.setPosition(bullet[i], Vector.add(this.portalPair.portal.position, { x: 250 * (Math.random() - 0.5), y: 250 * (Math.random() - 0.5) })); Matter.Body.setVelocity(bullet[i], { x: 0, y: 0 }); } } } // if (body.length) { for (let i = 0, len = body.length; i < len; i++) { if (body[i] !== m.holdingTarget) { // body[i].bounds.max.x - body[i].bounds.min.x < 100 && body[i].bounds.max.y - body[i].bounds.min.y < 100 if (Matter.Query.collides(this, [body[i]]).length === 0) { if (body[i].isInPortal === this) body[i].isInPortal = null } else if (body[i].isInPortal !== this) { //touching this portal, but for the first time if (isRemoveBlocks) { Matter.Composite.remove(engine.world, body[i]); body.splice(i, 1); break } body[i].isInPortal = this.portalPair //teleport if (this.portalPair.angle % (Math.PI / 2)) { //if left, right up or down Matter.Body.setPosition(body[i], this.portalPair.portal.position); } else { //if at some odd angle Matter.Body.setPosition(body[i], this.portalPair.position); } //rotate velocity let mag if (this.portalPair.angle !== 0 && this.portalPair.angle !== Math.PI) { //portal that fires the player up mag = Math.max(10, Math.min(50, body[i].velocity.y * 0.8)) + 11 } else { mag = Math.max(6, Math.min(50, Vector.magnitude(body[i].velocity))) } let v = Vector.mult(this.portalPair.unit, mag) Matter.Body.setVelocity(body[i], v); } } } // } //remove block if touching // if (body.length) { // touching = Matter.Query.collides(this, body) // for (let i = 0; i < touching.length; i++) { // if (touching[i].bodyB !== m.holdingTarget) { // for (let j = 0, len = body.length; j < len; j++) { // if (body[j] === touching[i].bodyB) { // body.splice(j, 1); // len-- // Matter.Composite.remove(engine.world, touching[i].bodyB); // break; // } // } // } // } // } // if (touching.length !== 0 && touching[0].bodyB !== m.holdingTarget) { // if (body.length) { // for (let i = 0; i < body.length; i++) { // if (body[i] === touching[0].bodyB) { // body.splice(i, 1); // break; // } // } // } // Matter.Composite.remove(engine.world, touching[0].bodyB); // } } const portalA = composite[composite.length] = Bodies.rectangle(centerA.x, centerA.y, width, height, { isSensor: true, angle: angleA, color: "hsla(197, 100%, 50%,0.7)", draw: draw, }); const portalB = composite[composite.length] = Bodies.rectangle(centerB.x, centerB.y, width, height, { isSensor: true, angle: angleB, color: "hsla(29, 100%, 50%, 0.7)", draw: draw }); const mapA = composite[composite.length] = Bodies.rectangle(centerA.x - 0.5 * unitA.x * mapWidth, centerA.y - 0.5 * unitA.y * mapWidth, mapWidth, height + 10, { collisionFilter: { category: cat.map, mask: cat.bullet | cat.powerUp | cat.mob | cat.mobBullet //cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet }, unit: unitA, angle: angleA, color: color.map, draw: draw, query: query, lastPortalCycle: 0 }); Matter.Body.setStatic(mapA, true); //make static Composite.add(engine.world, mapA); //add to world const mapB = composite[composite.length] = Bodies.rectangle(centerB.x - 0.5 * unitB.x * mapWidth, centerB.y - 0.5 * unitB.y * mapWidth, mapWidth, height + 10, { collisionFilter: { category: cat.map, mask: cat.bullet | cat.powerUp | cat.mob | cat.mobBullet //cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet }, unit: unitB, angle: angleB, color: color.map, draw: draw, query: query, lastPortalCycle: 0, }); Matter.Body.setStatic(mapB, true); //make static Composite.add(engine.world, mapB); //add to world mapA.portal = portalA mapB.portal = portalB mapA.portalPair = mapB mapB.portalPair = mapA return [portalA, portalB, mapA, mapB] }, drip(x, yMin, yMax, period = 100, color = "hsla(160, 100%, 35%, 0.5)") { return { x: x, y: yMin, period: period, dropCycle: 0, speed: 0, draw() { if (!m.isBodiesAsleep) { if (this.dropCycle < simulation.cycle) { //reset this.dropCycle = simulation.cycle + this.period + Math.floor(40 * Math.random()) this.y = yMin this.speed = 1 } else { //fall this.speed += 0.35 //acceleration from gravity this.y += this.speed } } if (this.y < yMax) { //draw ctx.fillStyle = color //"hsla(160, 100%, 35%,0.75)" ctx.beginPath(); ctx.arc(this.x, this.y, 8, 0, 2 * Math.PI); ctx.fill(); } } } }, isHazardRise: false, hazard(x, y, width, height, damage = 0.003) { return { min: { x: x, y: y }, max: { x: x + width, y: y + height }, width: width, height: height, maxHeight: height, isOn: true, opticalQuery() { if (this.isOn) { //draw ctx.fillStyle = `hsla(0, 100%, 50%,${0.6 + 0.4 * Math.random()})` ctx.fillRect(this.min.x, this.min.y, this.width, this.height) //collision with player if (this.height > 0 && Matter.Query.region([player], this).length && !(m.isCloak)) { if (m.immuneCycle < m.cycle) { m.immuneCycle = m.cycle + tech.collisionImmuneCycles; m.damage(damage) simulation.drawList.push({ //add dmg to draw queue x: player.position.x, y: player.position.y, radius: damage * 1500, color: simulation.mobDmgColor, time: 20 }); } } } }, query() { if (this.isOn) { ctx.fillStyle = "hsla(160, 100%, 35%,0.75)" const offset = 5 * Math.sin(simulation.cycle * 0.015) ctx.fillRect(this.min.x, this.min.y + offset, this.width, this.height - offset) if (this.height > 0 && Matter.Query.region([player], this).length) { if (m.immuneCycle < m.cycle) { const DRAIN = 0.002 * (tech.isRadioactiveResistance ? 0.25 : 1) + m.fieldRegen if (m.energy > DRAIN) { m.energy -= DRAIN m.damage(damage * (tech.isRadioactiveResistance ? 0.25 : 1) * 0.03) //still take 2% damage while you have energy } else { m.damage(damage * (tech.isRadioactiveResistance ? 0.25 : 1)) } } //float if (player.velocity.y > 5) player.force.y -= 0.95 * player.mass * simulation.g const slowY = (player.velocity.y > 0) ? Math.max(0.8, 1 - 0.002 * player.velocity.y * player.velocity.y) : Math.max(0.98, 1 - 0.001 * Math.abs(player.velocity.y)) //down : up Matter.Body.setVelocity(player, { x: Math.max(0.95, 1 - 0.036 * Math.abs(player.velocity.x)) * player.velocity.x, y: slowY * player.velocity.y }); //undo 1/2 of gravity player.force.y -= 0.5 * player.mass * simulation.g; } //float power ups powerUpCollide = Matter.Query.region(powerUp, this) for (let i = 0, len = powerUpCollide.length; i < len; i++) { const diameter = 2 * powerUpCollide[i].size const buoyancy = 1 - 0.2 * Math.max(0, Math.min(diameter, this.min.y - powerUpCollide[i].position.y + powerUpCollide[i].size)) / diameter powerUpCollide[i].force.y -= buoyancy * 1.14 * powerUpCollide[i].mass * simulation.g; Matter.Body.setVelocity(powerUpCollide[i], { x: powerUpCollide[i].velocity.x, y: 0.96 * powerUpCollide[i].velocity.y }); } } }, // draw() { // if (this.isOn) { // ctx.fillStyle = color // ctx.fillRect(this.min.x, this.min.y, this.width, this.height) // } // }, levelRise(growRate = 1) { if (this.height < this.maxHeight && !m.isBodiesAsleep) { this.height += growRate this.min.y -= growRate this.max.y = this.min.y + this.height } }, levelFall(fallRate = 1) { if (this.height > 0 && !m.isBodiesAsleep) { this.height -= fallRate this.min.y += fallRate this.max.y = this.min.y + this.height } }, level(isFill, growSpeed = 1) { if (!m.isBodiesAsleep) { if (isFill) { if (this.height < this.maxHeight) { this.height += growSpeed this.min.y -= growSpeed this.max.y = this.min.y + this.height } } else if (this.height > 0) { this.height -= growSpeed this.min.y += growSpeed this.max.y = this.min.y + this.height } } } } }, chain(x, y, angle = 0, isAttached = true, len = 15, radius = 20, stiffness = 1, damping = 1) { const gap = 2 * radius const unit = { x: Math.cos(angle), y: Math.sin(angle) } for (let i = 0; i < len; i++) { body[body.length] = Bodies.polygon(x + gap * unit.x * i, y + gap * unit.y * i, 12, radius, { inertia: Infinity, isNotHoldable: true }); } for (let i = 1; i < len; i++) { //attach blocks to each other consBB[consBB.length] = Constraint.create({ bodyA: body[body.length - i], bodyB: body[body.length - i - 1], stiffness: stiffness, damping: damping }); Composite.add(engine.world, consBB[consBB.length - 1]); } cons[cons.length] = Constraint.create({ //pin first block to a point in space pointA: { x: x, y: y }, bodyB: body[body.length - len], stiffness: 1, damping: damping }); Composite.add(engine.world, cons[cons.length - 1]); if (isAttached) { cons[cons.length] = Constraint.create({ //pin last block to a point in space pointA: { x: x + gap * unit.x * (len - 1), y: y + gap * unit.y * (len - 1) }, bodyB: body[body.length - 1], stiffness: 1, damping: damping }); Composite.add(engine.world, cons[cons.length - 1]); } }, //****************************************************************************************************************** //****************************************************************************************************************** //****************************************************************************************************************** //****************************************************************************************************************** labs() { level.isProcedural = true //used in generating text itn he level builder level.defaultZoom = 1700 simulation.zoomTransition(level.defaultZoom) document.body.style.backgroundColor = "#d9d9de" //"#d3d3db" //"#dcdcdf"; let isDoorLeft, isDoorRight, x, y doCustom = [] doCustomTopLayer = [] offset = { x: 0, y: 0 } const mobSpawnChance = 0 // Math.random() < chance + 0.07 * simulation.difficulty enterOptions = [ (x = offset.x, y = offset.y) => { //lasers level.setPosToSpawn(x + 1750, y - 800); spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); spawn.mapRect(x + 1450, y - 1350, 50, 450); //entrance left wall spawn.bodyRect(x + 1460, y - 900, 30, 150); //entrance door spawn.mapRect(x + 1600, y - 350, 500, 100); //toggle shelf const toggle = level.toggle(x + 1650, y - 350, true) //(x,y,isOn,isLockOn = true/false) let hazard if (Math.random() > 0.5) { spawn.mapRect(x + 550, y - 750, 1500, 50); //entrance shelf hazard = level.hazard(x + 850, y - 920, 600, 10, 0.4) //laser spawn.mapRect(x + 860, y - 925, 10, 20); //laser nose spawn.mapRect(x + 660, y - 975, 200, 120); //laser body } else { spawn.mapRect(x + 1350, y - 750, 700, 50); //entrance shelf hazard = level.hazard(x + 1040, y - 660, 1000, 10, 0.4) //laser spawn.mapRect(x + 1050, y - 665, 10, 20); //laser nose spawn.mapRect(x + 650, y - 705, 400, 100); //laser body } const hazard2 = level.hazard(x, y - 330, 450, 10, 0.4) //laser spawn.mapRect(x + 440, y - 335, 10, 20); //laser nose spawn.mapRect(x + 450, y - 375, 400, 100); //laser body //exit hazards const Xoffset = Math.floor(400 * Math.random()) const hazard3 = level.hazard(x + Xoffset, y - 1300, 10, 1300, 0.4) //laser spawn.mapRect(x + Xoffset - 5, y - 1310, 20, 20); //laser nose const Xoffset2 = 1650 + Math.floor(300 * Math.random()) const hazard4 = level.hazard(x + Xoffset2, y - 240, 10, 250, 0.4) //laser spawn.mapRect(x + Xoffset2 - 5, y - 250, 20, 20); //laser nose spawn.randomMob(x + 150, y + -1100, mobSpawnChance); spawn.randomMob(x + 175, y + -775, mobSpawnChance); spawn.randomMob(x + 150, y + -350, mobSpawnChance); spawn.randomMob(x + 150, y + -75, mobSpawnChance); spawn.randomMob(x + 650, y + -125, mobSpawnChance); spawn.randomMob(x + 1200, y + -75, mobSpawnChance); // let isSpawnedMobs = false doCustomTopLayer.push( () => { toggle.query(); hazard.isOn = toggle.isOn hazard2.isOn = toggle.isOn hazard3.isOn = toggle.isOn hazard4.isOn = toggle.isOn hazard.opticalQuery(); hazard2.opticalQuery(); hazard3.opticalQuery(); hazard4.opticalQuery(); // if (!isSpawnedMobs && !toggle.isOn) { // isSpawnedMobs = true // spawn.randomMob(x + 150, y + -1100, mobSpawnChance); // spawn.randomMob(x + 175, y + -775, mobSpawnChance); // spawn.randomMob(x + 150, y + -350, mobSpawnChance); // spawn.randomMob(x + 150, y + -75, mobSpawnChance); // spawn.randomMob(x + 650, y + -125, mobSpawnChance); // spawn.randomMob(x + 1200, y + -75, mobSpawnChance); // } } ) }, ] exitOptions = [ (x = offset.x, y = offset.y) => { level.exit.x = x + 1725; level.exit.y = y - 980; spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20); spawn.mapRect(x + 1500, y - 950, 500, 25); //exit platform spawn.mapRect(x + 1550, y - 1300, 25, 175); //exit side wall spawn.mapVertex(x + 1300, y - 125, "-400 0 -250 -400 250 -400 400 0"); spawn.bodyRect(x + 1075, y - 475, 125, 125, 0.25); spawn.bodyRect(x + 500, y - 100, 125, 100, 0.25); spawn.bodyRect(x + 200, y - 150, 100, 150, 0.25); spawn.bodyRect(x + 1075, y - 1075, 100, 125, 0.25); const density = 0.0015 //+ (simulation.difficultyMode < 5 ? 0.0035 : 0) const angle = Math.PI / 2 const variance = 0 //Math.PI const frictionAir = 0.03 const angularVelocity = 0 //0.01 const spinVariance = 0 //0.02 balance1 = level.spinner(x + 200, y - 500, 30, 400, density, angle + variance * (Math.random() - 0.5), frictionAir, angularVelocity + spinVariance * (Math.random() - 0.5)) // spinner(x, y, width, height, density = 0.001, angle=0,frictionAir=0.001,angularVelocity=0) { balance2 = level.spinner(x + 200, y - 950, 30, 400, density, angle + variance * (Math.random() - 0.5), frictionAir, angularVelocity + spinVariance * (Math.random() - 0.5)) balance3 = level.spinner(x + 650, y - 750, 30, 400, density, angle + variance * (Math.random() - 0.5), frictionAir, angularVelocity + spinVariance * (Math.random() - 0.5)) // balance4 = level.spinner(x + 750, y - 1050, 25, 350, density, angle + variance * (Math.random() - 0.5), frictionAir, angularVelocity + spinVariance * (Math.random() - 0.5)) balance4 = level.spinner(x + 1250, y - 1000, 30, 400, density, angle + variance * (Math.random() - 0.5), frictionAir, angularVelocity + spinVariance * (Math.random() - 0.5)) let isInRoom = false doCustom.push( () => { if (!isInRoom && m.pos.x > x - 100 && m.pos.x < x + 2700 && m.pos.y > y - 1300 && m.pos.y < y) { //check if player is in this room and run code once isInRoom = true spawn.randomMob(x + 1175, y - 725, mobSpawnChance); spawn.randomMob(x + 1450, y - 725, mobSpawnChance); spawn.randomMob(x + 425, y - 100, mobSpawnChance); spawn.randomMob(x + 1700, y - 300, mobSpawnChance); spawn.randomMob(x + 1300, y - 375, mobSpawnChance); } ctx.fillStyle = "#d4f4f4" ctx.fillRect(x + 1550, y - 1300, 450, 350) } ) doCustomTopLayer.push( () => { ctx.fillStyle = "#233" ctx.beginPath(); ctx.arc(balance1.pointA.x, balance1.pointA.y, 9, 0, 2 * Math.PI); ctx.moveTo(balance2.pointA.x, balance2.pointA.y) ctx.arc(balance2.pointA.x, balance2.pointA.y, 9, 0, 2 * Math.PI); ctx.moveTo(balance3.pointA.x, balance3.pointA.y) ctx.arc(balance3.pointA.x, balance3.pointA.y, 9, 0, 2 * Math.PI); ctx.moveTo(balance4.pointA.x, balance4.pointA.y) ctx.arc(balance4.pointA.x, balance4.pointA.y, 9, 0, 2 * Math.PI); ctx.fill(); } ) }, (x = offset.x, y = offset.y) => { level.exit.x = x + 1750; level.exit.y = y - 980; spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20); spawn.mapRect(x + 1550, y - 950, 500, 25); //exit platform spawn.mapRect(x + 1600, y - 1300, 25, 175); //exit side wall spawn.bodyRect(x + 1275, y - 475, 125, 125, 0.25); spawn.bodyRect(x + 500, y - 100, 125, 100, 0.25); spawn.bodyRect(x + 800, y - 150, 100, 150, 0.25); spawn.bodyRect(x + 875, y + -50, 50, 50); spawn.bodyRect(x + 1025, y + -50, 50, 50); if (Math.random() > 0.5) { const density = 0.0012 //+ (simulation.difficultyMode < 5 ? 0.003 : 0) const angle = Math.PI / 2 const variance = 0.2 //Math.PI const frictionAir = 0.015 const height = 35 balance1 = level.spinner(x + 1300, y - 425, height, 410, density, angle + variance * (Math.random() - 0.5), frictionAir) // spinner(x, y, width, height, density = 0.001, angle=0,frictionAir=0.001,angularVelocity=0) { balance3 = level.spinner(x + 750, y - 650, height, 410, density, angle + variance * (Math.random() - 0.5), frictionAir) balance2 = level.spinner(x + 300, y - 425, height, 410, density, angle + variance * (Math.random() - 0.5), frictionAir) balance4 = level.spinner(x + 1250, y - 950, 50, 550, density, angle, 0.1) const rotatingBlock = body[body.length - 1] doCustom.push( () => { if (!isInRoom && m.pos.x > x - 100 && m.pos.x < x + 2700 && m.pos.y > y - 1300 && m.pos.y < y) { //check if player is in this room and run code once isInRoom = true spawn.randomMob(x + 1175, y - 725, mobSpawnChance); spawn.randomMob(x + 1450, y - 725, mobSpawnChance); spawn.randomMob(x + 425, y - 100, mobSpawnChance); spawn.randomMob(x + 1200, y - 125, mobSpawnChance); spawn.randomMob(x + 1300, y - 375, mobSpawnChance); } ctx.fillStyle = "#d4f4f4" ctx.fillRect(x + 1600, y - 1300, 400, 350) rotatingBlock.torque += rotatingBlock.inertia * 0.000005 } ) } else { const density = 0.001 //+ (simulation.difficultyMode < 5 ? 0.003 : 0) const angle = Math.PI / 2 const variance = Math.PI const frictionAir = 0.015 const width = 200 const height = 200 const spinVariance = 0.05 balance1 = level.spinner(x + 175, y - 300, height, width, density, angle + variance * (Math.random() - 0.5), frictionAir, spinVariance * (Math.random() - 0.5)) // spinner(x, y, width, height, density = 0.001, angle=0,frictionAir=0.001,angularVelocity=0) { balance2 = level.spinner(x + 500, y - 525, height, width, density, angle + variance * (Math.random() - 0.5), frictionAir, spinVariance * (Math.random() - 0.5)) balance3 = level.spinner(x + 850, y - 700, height, width, density, angle + variance * (Math.random() - 0.5), frictionAir, spinVariance * (Math.random() - 0.5)) balance4 = level.spinner(x + 1250, y - 850, height, width, density, angle + variance * (Math.random() - 0.5), frictionAir, spinVariance * (Math.random() - 0.5)) doCustom.push( () => { if (!isInRoom && m.pos.x > x - 100 && m.pos.x < x + 2700 && m.pos.y > y - 1300 && m.pos.y < y) { //check if player is in this room and run code once isInRoom = true spawn.randomMob(x + 1175, y - 725, mobSpawnChance); spawn.randomMob(x + 1450, y - 725, mobSpawnChance); spawn.randomMob(x + 425, y - 100, mobSpawnChance); spawn.randomMob(x + 1200, y - 125, mobSpawnChance); spawn.randomMob(x + 1300, y - 375, mobSpawnChance); } ctx.fillStyle = "#d4f4f4" ctx.fillRect(x + 1600, y - 1300, 400, 350) } ) } let isInRoom = false doCustomTopLayer.push( () => { ctx.fillStyle = "#233" ctx.beginPath(); ctx.arc(balance1.pointA.x, balance1.pointA.y, 9, 0, 2 * Math.PI); ctx.moveTo(balance2.pointA.x, balance2.pointA.y) ctx.arc(balance2.pointA.x, balance2.pointA.y, 9, 0, 2 * Math.PI); ctx.moveTo(balance3.pointA.x, balance3.pointA.y) ctx.arc(balance3.pointA.x, balance3.pointA.y, 9, 0, 2 * Math.PI); ctx.moveTo(balance4.pointA.x, balance4.pointA.y) ctx.arc(balance4.pointA.x, balance4.pointA.y, 9, 0, 2 * Math.PI); ctx.fill(); } ) } ] emptyOptions = [ //nothing good here except the starting power up, and duplicated bosses (x = offset.x, y = offset.y) => { //pulse if (!isDoorLeft && isDoorRight) { //flipped, entering from the right powerUps.spawnStartingPowerUps(x + 2000 - 1650, y + -400); spawn.mapRect(x + 2000 - 1575 - 25, y + -625, 25, 375); //wall on top of wall spawn.mapRect(x + 2000 - 1575 - 25, y + -1325, 25, 525); //wall on top of wall spawn.mapRect(x + 2000 - 1525 - 250, y + -350, 250, 450); //wall spawn.mapRect(x + 2000 - 245 - 300, y + -200, 300, 100); //gun spawn.mapRect(x + 2000 - 530 - 25, y + -190, 25, 80); //gun nose const button = level.button(x + 2000 - 290 - 140, y - 200) button.isReadyToFire = true doCustom.push( () => { ctx.fillStyle = "rgba(0,0,0,0.05)"; //"rgba(0,0,0,0.1)"; ctx.fillRect(x + 2000 - 255 - 280, y + -100, 280, 100); button.query(); button.draw(); if (!button.isReadyToFire && button.isUp) { button.isReadyToFire = true } else if (button.isReadyToFire && !button.isUp) { button.isReadyToFire = false b.pulse(90, Math.PI, { x: x + 2000 - 560, y: y - 150 }) } } ) spawn.randomMob(x + 2000 - 1600, y + -425, mobSpawnChance); spawn.randomMob(x + 2000 - 1725, y + -1250, mobSpawnChance); spawn.randomMob(x + 2000 - 1250, y + -1200, mobSpawnChance); spawn.randomMob(x + 2000 - 300, y + -1200, mobSpawnChance); spawn.randomMob(x + 2000 - 800, y + -125, mobSpawnChance); let pick = spawn.pickList[Math.floor(Math.random() * spawn.pickList.length)]; spawn[pick](x + 2000 - 1275, y + -150, 90 + Math.random() * 40); //one extra large mob } else { powerUps.spawnStartingPowerUps(x + 1650, y + -400); spawn.mapRect(x + 1575, y + -625, 25, 375); //wall on top of wall spawn.mapRect(x + 1575, y + -1325, 25, 525); //wall on top of wall spawn.mapRect(x + 1525, y + -350, 250, 450); //wall spawn.mapRect(x + 245, y + -200, 300, 100); //gun spawn.mapRect(x + 530, y + -190, 25, 80); //gun nose const button = level.button(x + 290, y - 200) button.isReadyToFire = true doCustom.push( () => { ctx.fillStyle = "rgba(0,0,0,0.05)"; //"rgba(0,0,0,0.1)"; ctx.fillRect(x + 255, y + -100, 280, 100); button.query(); button.draw(); if (!button.isReadyToFire && button.isUp) { button.isReadyToFire = true } else if (button.isReadyToFire && !button.isUp) { button.isReadyToFire = false b.pulse(90, 0, { x: x + 560, y: y - 150 }) } } ) spawn.randomMob(x + 1600, y + -425, mobSpawnChance); spawn.randomMob(x + 1725, y + -1250, mobSpawnChance); spawn.randomMob(x + 1250, y + -1200, mobSpawnChance); spawn.randomMob(x + 300, y + -1200, mobSpawnChance); spawn.randomMob(x + 800, y + -125, mobSpawnChance); let pick = spawn.pickList[Math.floor(Math.random() * spawn.pickList.length)]; spawn[pick](x + 1275, y + -150, 90 + Math.random() * 40); //one extra large mob } }, (x = offset.x, y = offset.y) => { //spawn block and fire it if (!isDoorLeft && isDoorRight) { powerUps.spawnStartingPowerUps(x + 1650, y + -400); spawn.mapRect(x + 2000 - 1575 - 25, y + -625, 25, 375); //wall on top of wall spawn.mapRect(x + 2000 - 1575 - 25, y + -1325, 25, 525); //wall on top of wall spawn.mapRect(x + 2000 - 1525 - 250, y + -350, 250, 450); //wall spawn.mapRect(x + 2000 - 245 - 300, y + -200, 300, 100); //gun spawn.mapRect(x + 2000 - 530 - 25, y + -190, 25, 80); const button = level.button(x + 2000 - 290 - 140, y - 200) button.isReadyToFire = true doCustom.push( () => { ctx.fillStyle = "rgba(0,0,0,0.05)"; //"rgba(0,0,0,0.1)"; ctx.fillRect(x + 2000 - 255 - 280, y + -100, 280, 100); button.query(); button.draw(); if (!button.isReadyToFire && button.isUp) { button.isReadyToFire = true } else if (button.isReadyToFire && !button.isUp) { button.isReadyToFire = false fireBlock = function(xPos, yPos) { const index = body.length spawn.bodyRect(xPos, yPos, 35 + 50 * Math.random(), 35 + 50 * Math.random()); const bodyBullet = body[body.length - 1] Matter.Body.setVelocity(body[index], { x: -120, y: -5 }); body[index].collisionFilter.category = cat.body; body[index].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet body[index].classType = "body"; Composite.add(engine.world, body[index]); //add to world setTimeout(() => { //remove block for (let i = 0; i < body.length; i++) { if (body[i] === bodyBullet) { Matter.Composite.remove(engine.world, body[i]); body.splice(i, 1); } } }, 1000); } fireBlock(x + 2000 - 90 - 560 + 30 * Math.random(), y - 140); fireBlock(x + 2000 - 90 - 560 + 30 * Math.random(), y - 160); fireBlock(x + 2000 - 90 - 560 + 30 * Math.random(), y - 180); fireBlock(x + 2000 - 90 - 560 + 30 * Math.random(), y - 200); fireBlock(x + 2000 - 90 - 560 + 30 * Math.random(), y - 220); fireBlock(x + 2000 - 90 - 560 + 30 * Math.random(), y - 240); } } ) spawn.randomMob(x + 2000 - 1600, y + -425, mobSpawnChance); spawn.randomMob(x + 2000 - 1725, y + -1250, mobSpawnChance); spawn.randomMob(x + 2000 - 1250, y + -1200, mobSpawnChance); spawn.randomMob(x + 2000 - 300, y + -1200, mobSpawnChance); spawn.randomMob(x + 2000 - 800, y + -125, mobSpawnChance); let pick = spawn.pickList[Math.floor(Math.random() * spawn.pickList.length)]; spawn[pick](x + 2000 - 1275, y + -150, 90 + Math.random() * 40); //one extra large mob } else { powerUps.spawnStartingPowerUps(x + 1650, y + -400); spawn.mapRect(x + 1575, y + -625, 25, 375); //wall on top of wall spawn.mapRect(x + 1575, y + -1325, 25, 525); //wall on top of wall spawn.mapRect(x + 1525, y + -350, 250, 450); //wall spawn.mapRect(x + 245, y + -200, 300, 100); //gun spawn.mapRect(x + 530, y + -190, 25, 80); const button = level.button(x + 290, y - 200) button.isReadyToFire = true doCustom.push( () => { ctx.fillStyle = "rgba(0,0,0,0.05)"; //"rgba(0,0,0,0.1)"; ctx.fillRect(x + 255, y + -100, 280, 100); button.query(); button.draw(); if (!button.isReadyToFire && button.isUp) { button.isReadyToFire = true } else if (button.isReadyToFire && !button.isUp) { button.isReadyToFire = false fireBlock = function(xPos, yPos) { const index = body.length spawn.bodyRect(xPos, yPos, 35 + 50 * Math.random(), 35 + 50 * Math.random()); const bodyBullet = body[body.length - 1] Matter.Body.setVelocity(body[index], { x: 120, y: -5 }); body[index].collisionFilter.category = cat.body; body[index].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet body[index].classType = "body"; Composite.add(engine.world, body[index]); //add to world setTimeout(() => { //remove block for (let i = 0; i < body.length; i++) { if (body[i] === bodyBullet) { Matter.Composite.remove(engine.world, body[i]); body.splice(i, 1); } } }, 1000); } fireBlock(x + 560 + 30 * Math.random(), y - 140); fireBlock(x + 560 + 30 * Math.random(), y - 160); fireBlock(x + 560 + 30 * Math.random(), y - 180); fireBlock(x + 560 + 30 * Math.random(), y - 200); fireBlock(x + 560 + 30 * Math.random(), y - 220); fireBlock(x + 560 + 30 * Math.random(), y - 240); } } ) spawn.randomMob(x + 1600, y + -425, mobSpawnChance); spawn.randomMob(x + 1725, y + -1250, mobSpawnChance); spawn.randomMob(x + 1250, y + -1200, mobSpawnChance); spawn.randomMob(x + 300, y + -1200, mobSpawnChance); spawn.randomMob(x + 800, y + -125, mobSpawnChance); let pick = spawn.pickList[Math.floor(Math.random() * spawn.pickList.length)]; spawn[pick](x + 1275, y + -150, 90 + Math.random() * 40); //one extra large mob } }, (x = offset.x, y = offset.y) => { //fire an "ammo clip" of blocks if (!isDoorLeft && isDoorRight) { //flipped, entering from the right powerUps.spawnStartingPowerUps(x + 2000 - 1650, y + -400); spawn.mapRect(x + 2000 - 1575 - 25, y + -625, 25, 375); //wall on top of wall spawn.mapRect(x + 2000 - 1575 - 25, y + -1325, 25, 525); //wall on top of wall spawn.mapRect(x + 2000 - 1525 - 250, y + -350, 250, 450); //wall spawn.mapRect(x + 2000 - 175 - 370, y + -200, 370, 100); //gun spawn.mapRect(x + 2000 - 530 - 25, y + -190, 25, 80); spawn.mapRect(x + 2000 - 545 - 10, y + -770, 10, 325); //block loader for gun //walls spawn.mapRect(x + 2000 - 620 - 10, y + -770, 10, 325); //walls spawn.mapRect(x + 2000 + 50 - 150, y + -425, 150, 50); spawn.mapRect(x + 2000 - 175 - 370, y + -650, 370, 50); spawn.mapRect(x + 2000 - 540 - 95, y + -460, 95, 15); //bottom that opens and closes const bulletDoor = map[map.length - 1] //keep track of this body so it can be make non-collide later for (let i = 0; i < 6; i++) spawn.bodyRect(x + 2000 - 60 - 555 + Math.floor(Math.random() * 10), y + -520 - 50 * i, 50, 50); //bullets for gun spawn.bodyRect(x + 2000 - 250 - 40, y + -700, 40, 50); //extra bullets spawn.bodyRect(x + 2000 - 350 - 30, y + -700, 30, 35); spawn.bodyRect(x + 2000 - 425 - 40, y + -700, 40, 70); const button = level.button(x + 2000 - 280 - 140, y - 200) //trigger for gun button.isReadyToFire = true doCustom.push( () => { ctx.fillStyle = "rgba(0,0,0,0.05)"; //"rgba(0,0,0,0.1)"; ctx.fillRect(x + 2000 - 200 - 325, y + -625, 325, 650); button.query(); button.draw(); if (!button.isReadyToFire && button.isUp) { button.isReadyToFire = true bulletDoor.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet } else if (button.isReadyToFire && !button.isUp) { button.isReadyToFire = false bulletDoor.collisionFilter.mask = 0 //cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet } else if (!button.isUp) { const bounds = { min: { x: x + 2000 - 580, y: y - 125 }, max: { x: x + 2000 - 530, y: y - 110 } } const list = Matter.Query.region(body, bounds) for (let i = 0, len = list.length; i < len; i++) { Matter.Body.setVelocity(list[i], { x: -120, y: -5 }); } if (Matter.Query.region([player], bounds).length) { Matter.Body.setVelocity(player, { x: -100, y: -5 }); } ctx.fillStyle = `rgba(255,0,255,${0.2 + 0.7 * Math.random()})` ctx.fillRect(bounds.min.x, y - 185, 38, 70); } } ) spawn.randomMob(x + 2000 - 1600, y + -425, mobSpawnChance); spawn.randomMob(x + 2000 - 1725, y + -1250, mobSpawnChance); spawn.randomMob(x + 2000 - 1250, y + -1200, mobSpawnChance); spawn.randomMob(x + 2000 - 300, y + -1200, mobSpawnChance); spawn.randomMob(x + 2000 - 800, y + -125, mobSpawnChance); let pick = spawn.pickList[Math.floor(Math.random() * spawn.pickList.length)]; spawn[pick](x + 2000 - 1275, y + -150, 90 + Math.random() * 40); //one extra large mob } else { powerUps.spawnStartingPowerUps(x + 1650, y + -400); spawn.mapRect(x + 1575, y + -625, 25, 375); //wall on top of wall spawn.mapRect(x + 1575, y + -1325, 25, 525); //wall on top of wall spawn.mapRect(x + 1525, y + -350, 250, 450); //wall spawn.mapRect(x + 175, y + -200, 370, 100); //gun spawn.mapRect(x + 530, y + -190, 25, 80); spawn.mapRect(x + 545, y + -770, 10, 325); //block loader for gun //walls spawn.mapRect(x + 620, y + -770, 10, 325); //walls spawn.mapRect(x - 50, y + -425, 150, 50); spawn.mapRect(x + 175, y + -650, 370, 50); spawn.mapRect(x + 540, y + -460, 95, 15); //bottom that opens and closes const bulletDoor = map[map.length - 1] //keep track of this body so it can be make non-collide later for (let i = 0; i < 6; i++) spawn.bodyRect(x + 555 + Math.floor(Math.random() * 10), y + -520 - 50 * i, 50, 50); //bullets for gun spawn.bodyRect(x + 250, y + -700, 40, 50); //extra bullets spawn.bodyRect(x + 350, y + -700, 30, 35); spawn.bodyRect(x + 425, y + -700, 40, 70); const button = level.button(x + 280, y - 200) //trigger for gun button.isReadyToFire = true doCustom.push( () => { ctx.fillStyle = "rgba(0,0,0,0.05)"; //"rgba(0,0,0,0.1)"; ctx.fillRect(x + 200, y + -625, 325, 650); button.query(); button.draw(); if (!button.isReadyToFire && button.isUp) { button.isReadyToFire = true bulletDoor.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet } else if (button.isReadyToFire && !button.isUp) { button.isReadyToFire = false bulletDoor.collisionFilter.mask = 0 //cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet } else if (!button.isUp) { const bounds = { min: { x: x + 530, y: y - 125 }, max: { x: x + 580, y: y - 110 } } const list = Matter.Query.region(body, bounds) for (let i = 0, len = list.length; i < len; i++) { Matter.Body.setVelocity(list[i], { x: 120, y: -5 }); } if (Matter.Query.region([player], bounds).length) { Matter.Body.setVelocity(player, { x: 100, y: -5 }); } ctx.fillStyle = `rgba(255,0,255,${0.2 + 0.7 * Math.random()})` ctx.fillRect(bounds.min.x, y - 185, 38, 70); } } ) spawn.randomMob(x + 1600, y + -425, mobSpawnChance); spawn.randomMob(x + 1725, y + -1250, mobSpawnChance); spawn.randomMob(x + 1250, y + -1200, mobSpawnChance); spawn.randomMob(x + 300, y + -1200, mobSpawnChance); spawn.randomMob(x + 800, y + -125, mobSpawnChance); let pick = spawn.pickList[Math.floor(Math.random() * spawn.pickList.length)]; spawn[pick](x + 1275, y + -150, 90 + Math.random() * 40); //one extra large mob } } ] lootOptions = [ //has some power up reward //field, ammo, research, gun (x = offset.x, y = offset.y) => { spawn.mapRect(x + 1925, y + -325, 125, 150); //4 wall ledges spawn.mapRect(x + 1925, y + -865, 125, 150); //4 wall ledges spawn.mapRect(x + -50, y + -325, 125, 150); //4 wall ledges spawn.mapRect(x + -50, y + -865, 125, 150); //4 wall ledges spawn.mapRect(x + 1700, y + -500, 200, 25); spawn.mapRect(x + 75, y + -500, 200, 25); let chamberY = -650 if (Math.random() > 0.5) { //upper chamber chamberY = -650 - 640 spawn.mapRect(x + 550, y + -10 - 640, 900, 25); //raised floor spawn.mapRect(x + 450, y + -20 - 640, 1100, 25); spawn.mapRect(x + 450, y + -675 - 640, 1100, 25); //chamber ceiling powerUps.directSpawn(x + 998, y - 333 - 640, "tech", false); spawn.mapVertex(x + 1000, y + -0, "575 0 -575 0 -450 -100 450 -100"); //base } else { //lower chamber spawn.mapRect(x + 400, y + -10, 1200, 50); //raised floor spawn.mapRect(x + 450, y + -20, 1100, 50); spawn.mapRect(x + 450, y + -675, 1100, 25); //chamber ceiling spawn.mapRect(x + 550, y + -685, 900, 25); powerUps.directSpawn(x + 998, y - 333, "tech", false); } const powerUp1 = powerUp[powerUp.length - 1] powerUp1.holdPosition = { x: powerUp1.position.x, y: powerUp1.position.y } let isSpawnedMobs = false doCustom.push( () => { ctx.fillStyle = "#e4e4e9" //"rgba(255,255,255,1)"; ctx.fillRect(x + 450, y + chamberY, 1100, 650); //chamber background // if (!isInRoom && m.pos.x > x - 100 && m.pos.x < x + 2000 && m.pos.y > y - 1300 && m.pos.y < y) { //is player inside this room? // isInRoom = true // } else if (powerUp1.velocity.y !== 0) { //don't run this code if power up is gone //hack: powerUp1.velocity.y !== 0 seems to only be true if the power up up doesn't exist and is no longer being affected by gravity ctx.strokeStyle = "#f0f" ctx.lineWidth = 2; if (Vector.magnitudeSquared(Vector.sub(m.pos, powerUp1.position)) < 90000) { //zone radius is 300 //damage player and drain energy if (m.immuneCycle < m.cycle) { m.damage(0.01); if (m.energy > 0.1) m.energy -= 0.02 } //draw electricity going towards player const unit = Vector.normalise(Vector.sub(m.pos, powerUp1.position)) let xElec = powerUp1.position.x + 40 * unit.x; let yElec = powerUp1.position.y + 40 * unit.y; ctx.beginPath(); ctx.moveTo(xElec, yElec); const step = 40 for (let i = 0; i < 6; i++) { xElec += step * (unit.x + 1.5 * (Math.random() - 0.5)) yElec += step * (unit.y + 1.5 * (Math.random() - 0.5)) ctx.lineTo(xElec, yElec); } } else { //draw electricity going in random directions const angle = Math.random() * 2 * Math.PI const Dx = Math.cos(angle); const Dy = Math.sin(angle); let xElec = powerUp1.position.x + 40 * Dx; let yElec = powerUp1.position.y + 40 * Dy; ctx.beginPath(); ctx.moveTo(xElec, yElec); const step = 40 for (let i = 0; i < 6; i++) { xElec += step * (Dx + 1.5 * (Math.random() - 0.5)) yElec += step * (Dy + 1.5 * (Math.random() - 0.5)) ctx.lineTo(xElec, yElec); } } ctx.lineWidth = 2 * Math.random(); ctx.stroke(); //draw electricity ctx.beginPath(); //outline damage zone ctx.arc(powerUp1.position.x, powerUp1.position.y, 300, 0, 2 * Math.PI); ctx.stroke(); //float power up in the air Matter.Body.setPosition(powerUp1, { x: powerUp1.holdPosition.x + 4 * Math.random(), //1300 -2 y: powerUp1.holdPosition.y + 4 * Math.random() //335 -2 }); Matter.Body.setVelocity(powerUp1, { x: 0, y: 0 }); } else if (!isSpawnedMobs) { isSpawnedMobs = true if (chamberY === -650) { //lower chamber spawn.randomMob(x + 250, y + -650, mobSpawnChance); spawn.randomMob(x + 1825, y + -600, mobSpawnChance); spawn.randomGroup(x + 275, y + -1050, mobSpawnChance); spawn.randomGroup(x + 675, y + -975, mobSpawnChance); spawn.randomGroup(x + 1225, y + -975, Infinity); } else { //upper chamber spawn.randomMob(x + 250, y + -650, mobSpawnChance); spawn.randomMob(x + 1800, y + -625, mobSpawnChance); spawn.randomGroup(x + 300, y + -300, mobSpawnChance); spawn.randomGroup(x + 650, y + -275, mobSpawnChance); spawn.randomGroup(x + 1125, y + -300, Infinity); } } } ) } ] upDownOptions = [ //extra tall vertical section 3000x3000 //this is where the level boss is // (x = offset.x, y = offset.y) => { // // spawn.mapVertex(x + 5, y + -1318, "0 0 0 -250 125 -250"); //left ledges // // spawn.mapVertex(x + 1995, y + -1318, "0 0 0 -250 -125 -250"); // right ledges // let r = 150 // const hexagon = `${r} 0 ${r*Math.cos(5.236)} ${r*Math.sin(5.236)} ${r*Math.cos(4.189)} ${r*Math.sin(4.189)} ${-r} 0 ${r*Math.cos(2.0944)} ${r*Math.sin(2.0944)} ${r*Math.cos(1.0472)} ${r*Math.sin(1.0472)} ` // //450 horizontal spread // -130-130-130 = 390 vertical // let xOff = 100 + 225 // spawn.mapVertex(x + xOff + 0 * 450, y + -260 - 0 * 390, hexagon); // spawn.mapVertex(x + xOff + 1 * 450, y + -260 - 0 * 390, hexagon); // spawn.mapVertex(x + xOff + 2 * 450, y + -260 - 0 * 390, hexagon); // spawn.mapVertex(x + xOff + 3 * 450, y + -260 - 0 * 390, hexagon); // xOff = 100 // // spawn.mapVertex(x + xOff + 0 * 450, y + 1 * -260 - 1 * 390, hexagon); // spawn.mapVertex(x + xOff + 1 * 450, y + -260 - 1 * 390, hexagon); // spawn.mapVertex(x + xOff + 2 * 450, y + -260 - 1 * 390, hexagon); // spawn.mapVertex(x + xOff + 3 * 450, y + -260 - 1 * 390, hexagon); // // spawn.mapVertex(x + xOff + 4 * 450, y + 1 * -260 - 1 * 390, hexagon); // xOff = 100 + 225 // spawn.mapVertex(x + xOff + 0 * 450, y + -260 - 2 * 390, hexagon); // spawn.mapVertex(x + xOff + 1 * 450, y + -260 - 2 * 390, hexagon); // spawn.mapVertex(x + xOff + 2 * 450, y + -260 - 2 * 390, hexagon); // spawn.mapVertex(x + xOff + 3 * 450, y + -260 - 2 * 390, hexagon); // xOff = 100 // // spawn.mapVertex(x + xOff + 0 * 450, y + 1 * -260 - 1 * 390, hexagon); // spawn.mapVertex(x + xOff + 1 * 450, y + -260 - 3 * 390, hexagon); // spawn.mapVertex(x + xOff + 2 * 450, y + -260 - 3 * 390, hexagon); // spawn.mapVertex(x + xOff + 3 * 450, y + -260 - 3 * 390, hexagon); // // spawn.mapVertex(x + xOff + 4 * 450, y + 1 * -260 - 1 * 390, hexagon); // xOff = 100 + 225 // spawn.mapVertex(x + xOff + 0 * 450, y + -260 - 4 * 390, hexagon); // spawn.mapVertex(x + xOff + 1 * 450, y + -260 - 4 * 390, hexagon); // spawn.mapVertex(x + xOff + 2 * 450, y + -260 - 4 * 390, hexagon); // spawn.mapVertex(x + xOff + 3 * 450, y + -260 - 4 * 390, hexagon); // //phase 2 // xOff = 100 // spawn.mapVertex(x + xOff + 1 * 450, y + -130 - 0 * 390, hexagon); // spawn.mapVertex(x + xOff + 2 * 450, y + -130 - 0 * 390, hexagon); // spawn.mapVertex(x + xOff + 3 * 450, y + -130 - 0 * 390, hexagon); // xOff = 100 + 225 // spawn.mapVertex(x + xOff + 0 * 450, y + -130 - 1 * 390, hexagon); // spawn.mapVertex(x + xOff + 1 * 450, y + -130 - 1 * 390, hexagon); // spawn.mapVertex(x + xOff + 2 * 450, y + -130 - 1 * 390, hexagon); // spawn.mapVertex(x + xOff + 3 * 450, y + -130 - 1 * 390, hexagon); // spawn.mapVertex(x + xOff + 4 * 450, y + -130 - 1 * 390, hexagon); // xOff = 100 // spawn.mapVertex(x + xOff + 1 * 450, y + -130 - 2 * 390, hexagon); // spawn.mapVertex(x + xOff + 2 * 450, y + -130 - 2 * 390, hexagon); // spawn.mapVertex(x + xOff + 3 * 450, y + -130 - 2 * 390, hexagon); // // spawn.mapVertex(x + 550, y + 1 * -260, hexagon); // // spawn.mapVertex(x + 550, y + 2 * -260, hexagon); // // spawn.mapVertex(x + 550, y + 3 * -260, hexagon); // // spawn.mapVertex(x + 550, y + 5 * -260, hexagon); // // spawn.mapVertex(x + 550, y + 4 * -260, hexagon); // // spawn.mapVertex(x + 775, y + -260, hexagon); // // spawn.mapVertex(x + 1225, y + -260, hexagon); // // spawn.mapVertex(x + 550, y + -650, hexagon); // // spawn.mapVertex(x + 1000, y + -650, hexagon); // // spawn.mapVertex(x + 1450, y + -650, hexagon); // // spawn.mapVertex(x + 775, y + -1040, hexagon); // // spawn.mapVertex(x + 1225, y + -1040, hexagon); // // spawn.mapVertex(x + 550, y + -1430, hexagon); // // spawn.mapVertex(x + 1000, y + -1430, hexagon); // // spawn.mapVertex(x + 1450, y + -1430, hexagon); // // spawn.mapVertex(x + 775, y + -1820, hexagon); // // spawn.mapVertex(x + 1225, y + -1820, hexagon); // let count = 0 // doCustomTopLayer.push( // () => { // if (!(count % 60)) { // addMapToLevelInProgress = (who) => { //adds new map elements to the level while the level is already running //don't forget to run simulation.draw.setPaths() after you all the the elements so they show up visually // who.collisionFilter.category = cat.map; // who.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet; // Matter.Body.setStatic(who, true); //make static // Composite.add(engine.world, who); //add to world // } // const numberOfMapElementsAdded = 0 // for (let i = 0; i < numberOfMapElementsAdded; i++) addMapToLevelInProgress(map[map.length - 1 - i]) // simulation.draw.setPaths() //update map graphics // } // }) // spawn.randomMob(x + 225, y + -1025, mobSpawnChance); // spawn.randomMob(x + 200, y + -675, mobSpawnChance); // spawn.randomMob(x + 225, y + -200, mobSpawnChance); // spawn.randomMob(x + 1750, y + -1075, mobSpawnChance); // spawn.randomMob(x + 1700, y + -650, mobSpawnChance); // spawn.randomMob(x + 1675, y + -175, mobSpawnChance); // spawn.randomGroup(x + 300, y + -2200); // spawn.randomGroup(x + 1625, y + -2200); // spawn.randomLevelBoss(x + 950, y + -2200); // }, (x = offset.x, y = offset.y) => { const toggle = level.toggle(x + 950, y + 0, false, true) // toggle(x, y, isOn = false, isLockOn = false) { toggle.isAddedElements = false spawn.mapVertex(x + 5, y + -1318, "0 0 0 -250 125 -250"); //left ledges spawn.mapVertex(x + 1995, y + -1318, "0 0 0 -250 -125 -250"); // right ledges doCustomTopLayer.push( () => { toggle.query(); if (toggle.isOn && !toggle.isAddedElements) { //this code runs once after the toggle is triggered toggle.isAddedElements = true //only do this once addMapToLevelInProgress = (who) => { //adds new map elements to the level while the level is already running //don't forget to run simulation.draw.setPaths() after you all the the elements so they show up visually who.collisionFilter.category = cat.map; who.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet; Matter.Body.setStatic(who, true); //make static Composite.add(engine.world, who); //add to world } let r = 150 let hexagon = `${r} 0 ${r * Math.cos(5.236)} ${r * Math.sin(5.236)} ${r * Math.cos(4.189)} ${r * Math.sin(4.189)} ${-r} 0 ${r * Math.cos(2.0944)} ${r * Math.sin(2.0944)} ${r * Math.cos(1.0472)} ${r * Math.sin(1.0472)} ` //450 horizontal spread // -130-130-130 = 390 vertical if (Math.random() < 0.5) { spawn.mapVertex(x + 775, y + -260, hexagon); spawn.mapVertex(x + 1225, y + -260, hexagon); spawn.mapVertex(x + 550, y + -650, hexagon); spawn.mapVertex(x + 1000, y + -650, hexagon); spawn.mapVertex(x + 1450, y + -650, hexagon); spawn.mapVertex(x + 325, y + -1040, hexagon); spawn.mapVertex(x + 775, y + -1040, hexagon); spawn.mapVertex(x + 1225, y + -1040, hexagon); spawn.mapVertex(x + 1675, y + -1040, hexagon); spawn.mapVertex(x + 550, y + -1430, hexagon); spawn.mapVertex(x + 1000, y + -1430, hexagon); spawn.mapVertex(x + 1450, y + -1430, hexagon); const numberOfMapElementsAdded = 12 for (let i = 0; i < numberOfMapElementsAdded; i++) addMapToLevelInProgress(map[map.length - 1 - i]) spawn.randomMob(x + 225, y + -1775, mobSpawnChance); spawn.randomMob(x + 700, y + -1750, mobSpawnChance); spawn.randomMob(x + 1175, y + -1725, mobSpawnChance); spawn.randomMob(x + 1700, y + -1700, mobSpawnChance); spawn.randomMob(x + 1750, y + -250, mobSpawnChance); spawn.randomMob(x + 125, y + -250, mobSpawnChance); } else { spawn.mapVertex(x + 775, y + -260, hexagon); spawn.mapVertex(x + 1225, y + -260, hexagon); spawn.mapVertex(x + 550, y + -650, hexagon); spawn.mapVertex(x + 1000, y + -650, hexagon); spawn.mapVertex(x + 1450, y + -650, hexagon); spawn.mapVertex(x + 775, y + -1040, hexagon); spawn.mapVertex(x + 1225, y + -1040, hexagon); spawn.mapVertex(x + 550, y + -1430, hexagon); spawn.mapVertex(x + 1000, y + -1430, hexagon); spawn.mapVertex(x + 1450, y + -1430, hexagon); spawn.mapVertex(x + 775, y + -1820, hexagon); spawn.mapVertex(x + 1225, y + -1820, hexagon); const numberOfMapElementsAdded = 12 for (let i = 0; i < numberOfMapElementsAdded; i++) addMapToLevelInProgress(map[map.length - 1 - i]) spawn.randomMob(x + 225, y + -1025, mobSpawnChance); spawn.randomMob(x + 200, y + -675, mobSpawnChance); spawn.randomMob(x + 225, y + -200, mobSpawnChance); spawn.randomMob(x + 1750, y + -1075, mobSpawnChance); spawn.randomMob(x + 1700, y + -650, mobSpawnChance); spawn.randomMob(x + 1675, y + -175, mobSpawnChance); } simulation.draw.setPaths() //update map graphics spawn.randomGroup(x + 300, y + -2200); spawn.randomGroup(x + 1625, y + -2200); spawn.randomLevelBoss(x + 700, y + -2300); spawn.secondaryBossChance(x + 1250, y + -2300) } } ) }, (x = offset.x, y = offset.y) => { const toggle = level.toggle(x + 950, y + 0, false, true) // toggle(x, y, isOn = false, isLockOn = false) { toggle.isAddedElements = false //left ledges spawn.mapVertex(x + 5, y + -1868, "0 0 0 -250 125 -250"); spawn.mapVertex(x + 5, y + -1318, "0 0 0 -250 125 -250"); //door spawn.mapVertex(x + 5, y + -768, "0 0 0 -250 125 -250"); // right ledges spawn.mapVertex(x + 2000, y + -1868, "0 0 0 -250 -125 -250"); spawn.mapVertex(x + 2000, y + -1318, "0 0 0 -250 -125 -250"); //door spawn.mapVertex(x + 2000, y + -768, "0 0 0 -250 -125 -250"); doCustomTopLayer.push( () => { toggle.query(); if (toggle.isOn && !toggle.isAddedElements) { //this code runs once after the toggle is triggered toggle.isAddedElements = true //only do this once addMapToLevelInProgress = (who) => { //adds new map elements to the level while the level is already running //don't forget to run simulation.draw.setPaths() after you all the the elements so they show up visually who.collisionFilter.category = cat.map; who.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet; Matter.Body.setStatic(who, true); //make static Composite.add(engine.world, who); //add to world } //right side hexagons let r = 300 let hexagon = `${r} 0 ${r * Math.cos(5.236)} ${r * Math.sin(5.236)} ${r * Math.cos(4.189)} ${r * Math.sin(4.189)} ${-r} 0 ${r * Math.cos(2.0944)} ${r * Math.sin(2.0944)} ${r * Math.cos(1.0472)} ${r * Math.sin(1.0472)} ` spawn.mapVertex(x + 1640, y + -365, hexagon); // r = 275 // let hexagonHalf = `${r} 0 ${r*Math.cos(5.236)} ${r*Math.sin(5.236)} ${r*Math.cos(4.189)} ${r*Math.sin(4.189)} ${-r} 0 ` // spawn.mapVertex(x + 2300, y + -75, hexagonHalf); r = 150 const hexagon150 = `${r} 0 ${r * Math.cos(5.236)} ${r * Math.sin(5.236)} ${r * Math.cos(4.189)} ${r * Math.sin(4.189)} ${-r} 0 ${r * Math.cos(2.0944)} ${r * Math.sin(2.0944)} ${r * Math.cos(1.0472)} ${r * Math.sin(1.0472)} ` // spawn.mapVertex(x + 1750, y + -550, hexagon150); spawn.mapVertex(x + 1750, y + -1100, hexagon150); spawn.mapVertex(x + 1750, y + -1650, hexagon150); spawn.mapVertex(x + 1750, y + -2200, hexagon150); //left side r = 350 let hexagonHalf = `${r} 0 ${r * Math.cos(5.236)} ${r * Math.sin(5.236)} ${r * Math.cos(4.189)} ${r * Math.sin(4.189)} ${-r} 0 ` spawn.mapVertex(x + 425, y + -90, hexagonHalf); spawn.mapVertex(x + 850, y + -500, hexagon150); spawn.mapVertex(x + 550, y + -850, hexagon150); spawn.mapVertex(x + 250, y + -1200, hexagon150); spawn.mapVertex(x + 250, y + -1700, hexagon150); spawn.mapVertex(x + 725, y + -1950, hexagon150); spawn.mapVertex(x + 1200, y + -2200, hexagon150); const numberOfMapElementsAdded = 11 for (let i = 0; i < numberOfMapElementsAdded; i++) addMapToLevelInProgress(map[map.length - 1 - i]) spawn.randomMob(x + 1075, y + -1500, mobSpawnChance); spawn.randomMob(x + 325, y + -550, mobSpawnChance); spawn.randomMob(x + 800, y + -925, mobSpawnChance); spawn.randomMob(x + 1400, y + -1250, mobSpawnChance); spawn.randomMob(x + 1350, y + -1725, mobSpawnChance); spawn.randomMob(x + 575, y + -1375, mobSpawnChance); spawn.randomMob(x + 225, y + -2275, mobSpawnChance); spawn.randomMob(x + 875, y + -2450, mobSpawnChance); spawn.randomMob(x + 1550, y + -2525, mobSpawnChance); spawn.randomLevelBoss(x + 1075, y + -1500); spawn.secondaryBossChance(x + 1200, y + -1000) simulation.draw.setPaths() //update map graphics } } ) }, // (x = offset.x, y = offset.y) => { // const elevator1 = level.elevator(x + 1100, y - 200, 250, 30, -2100, 0.0015) // x, y, width, height, maxHeight, force = 0.003, friction = { up: 0.01, down: 0.2 }, isTeleport = false) { // // const elevator1 = level.elevator(x + 175, y - 200, 250, 30, -1400, 0.001) // // const elevator2 = level.elevator(x + 2175, y - 200, 250, 30, -1400, 0.001) // spawn.mapRect(-200, -1400, 350, 50); //up left door ledge // spawn.mapRect(2450, -1400, 350, 50); //up right door ledge // spawn.mapRect(225, -450, 350, 350); //left crawl zone // // spawn.mapRect(725, -175, 275, 75); // spawn.mapRect(725, -225, 350, 100); // spawn.mapRect(275, -750, 200, 200); // spawn.mapRect(1375, -700, 500, 750); //right side big elevator wall // spawn.mapRect(2375, -325, 350, 50); // spawn.mapRect(1800, -500, 250, 50); // //up high elevator // spawn.mapRect(1375, -2100, 500, 175); // spawn.mapRect(600, -2100, 475, 175); // if (simulation.difficulty > 3) spawn.randomLevelBoss(x + 1250, y - 1400); // doCustomTopLayer.push( // () => { // elevator1.move() // } // ) // } ] //pick which type of room spawns enter = enterOptions[Math.floor(Math.random() * enterOptions.length)]; exit = exitOptions[Math.floor(Math.random() * exitOptions.length)]; empty = emptyOptions[Math.floor(Math.random() * emptyOptions.length)]; loot = lootOptions[Math.floor(Math.random() * lootOptions.length)]; upDown = upDownOptions[Math.floor(Math.random() * upDownOptions.length)]; // upDown = upDownOptions[1] //controls what level spawns for map designing building //********************************* DO !NOT! RUN THIS LINE IN THE FINAL VERSION *************************************** //3x2: 4 short rooms (3000x1500), 1 double tall room (3000x3000) //rooms let rooms = ["exit", "loot", "enter", "empty"] rooms = shuffle(rooms); //shuffles array order //look... you and I both know there is a better way to do this, but it works so I'm gonna focus on other things while ( //makes sure that the exit and entrance aren't both on the same floor (rooms[0] === "enter" && rooms[2] === "exit") || (rooms[2] === "enter" && rooms[0] === "exit") || (rooms[1] === "enter" && rooms[3] === "exit") || (rooms[3] === "enter" && rooms[1] === "exit") ) rooms = shuffle(rooms); //shuffles array order for (let i = 0; i < rooms.length; i++) { if (rooms[i] === "enter") rooms[i] = enter if (rooms[i] === "exit") rooms[i] = exit if (rooms[i] === "empty") rooms[i] = empty if (rooms[i] === "loot") rooms[i] = loot } // rooms = [enter, exit, loot, empty, ] //controls what level spawns for map designing building //********************************* DO !NOT! RUN THIS LINE IN THE FINAL VERSION *************************************** outline = (isLower = true) => { spawn.mapRect(offset.x - 100, offset.y - 1400, 2100, 100); //ceiling if (isLower) spawn.mapRect(offset.x - 100, offset.y, 2200, 100); //only draw floor if on the lower level if (!isDoorLeft) spawn.mapRect(offset.x - 100, offset.y - 1400, 100, 1500); //left wall if (isDoorRight) { //if door only add wall on right side spawn.mapRect(offset.x + 2000, offset.y - 1400, 100, 1225); //right wall spawn.mapRect(offset.x + 2000, offset.y - 10, 100, 20); //right doorstep const doorWidth = 15 + Math.floor(100 * Math.random() * Math.random()) spawn.bodyRect(offset.x + 2050 - doorWidth / 2, offset.y - 175, doorWidth, 165); //block door } else { spawn.mapRect(offset.x + 2000, offset.y - 1400, 100, 1500); //right wall } } outlineUpDown = () => { spawn.mapRect(offset.x - 100, offset.y + 0, 2100, 100); //floor spawn.mapRect(offset.x - 100, offset.y - 2800, 2100, 100); //ceiling if (!isDoorLeft) spawn.mapRect(offset.x - 100, offset.y - 2800, 100, 2900); //left wall if (isDoorRight) { //if door only add wall on right side //upper door spawn.mapRect(offset.x + 2000, offset.y - 2800, 100, 1225); //right wall spawn.mapRect(offset.x + 2000, offset.y - 1410, 100, 20); //right doorstep const doorWidth = 15 + Math.floor(100 * Math.random() * Math.random()) spawn.bodyRect(offset.x + 2050 - doorWidth / 2, offset.y - 1575, doorWidth, 165); //block door //lower door spawn.mapRect(offset.x + 2000, offset.y - 1400, 100, 1225); //right wall spawn.mapRect(offset.x + 2000, offset.y - 10, 100, 20); //right doorstep const doorWidth2 = 15 + Math.floor(100 * Math.random() * Math.random()) spawn.bodyRect(offset.x + 2050 - doorWidth2 / 2, offset.y - 175, doorWidth2, 165); //block door } else { spawn.mapRect(offset.x + 2000, offset.y - 2800, 100, 2900); //right wall } } let columns = [ () => { offset.y = 0 outlineUpDown() upDown() }, () => { offset.y = 0 outline() rooms[0]() offset.y = -1400 outline(false) rooms[1]() }, () => { offset.y = 0 outline() rooms[2]() offset.y = -1400 outline(false) rooms[3]() }, ] columns = shuffle(columns) //********************************* RUN THIS LINE IN THE FINAL VERSION *************************************** for (let i = 0; i < 3; i++) { if (i === 0) { isDoorLeft = false isDoorRight = true } else if (i === 1) { isDoorLeft = true isDoorRight = true } else { isDoorLeft = true isDoorRight = false } offset.x = i * 2100 columns[i]() } level.custom = () => { for (let i = 0, len = doCustom.length; i < len; i++) doCustom[i]() //runs all the active code from each room level.exit.drawAndCheck(); level.enter.draw(); }; level.customTopLayer = () => { for (let i = 0, len = doCustomTopLayer.length; i < len; i++) doCustomTopLayer[i]() //runs all the active code from each room }; powerUps.addResearchToLevel() //needs to run after mobs are spawned // level.setPosToSpawn(850, -40); //********************************* DO !NOT! RUN THIS LINE IN THE FINAL VERSION *************************************** }, null() { level.levels.pop(); //remove lore level from rotation // level.onLevel-- // console.log(level.onLevel, level.levels) //start a conversation based on the number of conversations seen if (localSettings.loreCount < lore.conversation.length && !simulation.isCheating) { lore.testSpeechAPI() //see if speech is working lore.chapter = localSettings.loreCount //set the chapter to listen to to be the lore level (you can't use the lore level because it changes during conversations) lore.sentence = 0 //what part of the conversation to start on lore.conversation[lore.chapter][lore.sentence]() localSettings.loreCount++ //hear the next conversation next time you win if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage } // const hazardSlime = level.hazard(-1800, 150, 3600, 650, 0.004, "hsla(160, 100%, 35%,0.75)") level.isHazardRise = false //this is set to true to make the slime rise up const hazardSlime = level.hazard(-1800, -800, 3600, 1600, 0.004, "hsla(160, 100%, 35%,0.75)") hazardSlime.height -= 950 hazardSlime.min.y += 950 hazardSlime.max.y = hazardSlime.min.y + hazardSlime.height const circle = { x: 0, y: -500, radius: 50 } level.custom = () => { //draw wide line ctx.beginPath(); ctx.moveTo(circle.x, -800) ctx.lineTo(circle.x, circle.y) ctx.lineWidth = 40; ctx.strokeStyle = lore.talkingColor //"#d5dddd" //"#bcc"; ctx.globalAlpha = 0.03; ctx.stroke(); ctx.globalAlpha = 1; //support pillar ctx.fillStyle = "rgba(0,0,0,0.2)"; ctx.fillRect(-25, 0, 50, 1000); //draw circles ctx.beginPath(); ctx.arc(circle.x, circle.y, circle.radius, 0, 2 * Math.PI); ctx.fillStyle = "#bcc" ctx.fill(); ctx.lineWidth = 2; ctx.strokeStyle = "#abb"; ctx.stroke(); ctx.beginPath(); ctx.arc(circle.x, circle.y, circle.radius / 8, 0, 2 * Math.PI); ctx.fillStyle = lore.talkingColor //"#dff" ctx.fill(); // level.enter.draw(); }; let sway = { x: 0, y: 0 } let phase = -Math.PI / 2 level.customTopLayer = () => { ctx.fillStyle = "rgba(0,0,0,0.1)"; ctx.fillRect(-1950, -950, 3900, 1900); //draw center circle lines ctx.beginPath(); const step = Math.PI / 20 const horizontalStep = 85 if (simulation.isCheating) phase += 0.3 * Math.random() * Math.random() //(m.pos.x - circle.x) * 0.0005 //0.05 * Math.sin(simulation.cycle * 0.030) // const sway = 5 * Math.cos(simulation.cycle * 0.007) sway.x = sway.x * 0.995 + 0.005 * (m.pos.x - circle.x) * 0.05 //+ 0.04 * Math.cos(simulation.cycle * 0.01) sway.y = 2.5 * Math.sin(simulation.cycle * 0.015) for (let i = -19.5; i < 20; i++) { const where = { x: circle.x + circle.radius * Math.cos(i * step + phase), y: circle.y + circle.radius * Math.sin(i * step + phase) } ctx.moveTo(where.x, where.y); ctx.bezierCurveTo(sway.x * Math.abs(i) + where.x, where.y + 25 * Math.abs(i) + 60 + sway.y * Math.sqrt(Math.abs(i)), sway.x * Math.abs(i) + where.x + horizontalStep * i, where.y + 25 * Math.abs(i) + 60 + sway.y * Math.sqrt(Math.abs(i)), horizontalStep * i, -800); } ctx.lineWidth = 0.5; ctx.strokeStyle = "#899"; ctx.stroke(); hazardSlime.query(); if (level.isHazardRise) hazardSlime.level(true) //draw wires // ctx.beginPath(); // ctx.moveTo(-500, -800); // ctx.quadraticCurveTo(-800, -100, -1800, -375); // ctx.moveTo(-600, -800); // ctx.quadraticCurveTo(-800, -200, -1800, -325); // ctx.lineWidth = 1; // ctx.strokeStyle = "#9aa"; // ctx.stroke(); }; level.setPosToSpawn(0, -50); //normal spawn spawn.mapRect(level.enter.x, level.enter.y + 25, 100, 10); level.exit.x = 0; level.exit.y = 40000; level.defaultZoom = 1000 simulation.zoomTransition(level.defaultZoom) // document.body.style.backgroundColor = "#aaa"; document.body.style.backgroundColor = "#ddd"; spawn.mapRect(-3000, 800, 5000, 1200); //bottom spawn.mapRect(-2000, -2000, 5000, 1200); //ceiling spawn.mapRect(-3000, -2000, 1200, 3400); //left spawn.mapRect(1800, -1400, 1200, 3400); //right spawn.mapRect(-500, 0, 1000, 50); //center platform spawn.mapRect(-500, -25, 25, 50); //edge shelf spawn.mapRect(475, -25, 25, 50); //edge shelf }, testing() { const button = level.button(1000, 0) spawn.bodyRect(1000, -50, 50, 50); level.custom = () => { ctx.fillStyle = "rgba(0,255,255,0.1)"; ctx.fillRect(6400, -550, 300, 350); level.exit.drawAndCheck(); level.enter.draw(); }; level.customTopLayer = () => { button.query(); button.draw(); }; level.setPosToSpawn(0, -450); //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 level.defaultZoom = 1500 simulation.zoomTransition(level.defaultZoom) document.body.style.backgroundColor = color.background //"#ddd"; spawn.mapRect(-950, 0, 8200, 800); //ground spawn.mapRect(-950, -1200, 800, 1400); //left wall spawn.mapRect(-950, -1800, 8200, 800); //roof spawn.mapRect(-250, -400, 1000, 600); // shelf spawn.mapRect(-250, -1200, 1000, 550); // shelf roof // for (let i = 0; i < 10; ++i) powerUps.spawn(550, -800, "ammo", false); function blockDoor(x, y, blockSize = 58) { spawn.mapRect(x, y - 290, 40, 60); // door lip spawn.mapRect(x, y, 40, 50); // door lip for (let i = 0; i < 4; ++i) spawn.bodyRect(x + 5, y - 260 + i * blockSize, 30, blockSize); } spawn.mapRect(2500, -1200, 200, 750); //right wall spawn.mapRect(2500, -200, 200, 300); //right wall spawn.mapRect(4500, -1200, 200, 650); //right wall blockDoor(4585, -310) spawn.mapRect(4500, -300, 200, 400); //right wall spawn.mapRect(6400, -1200, 400, 750); //right wall spawn.mapRect(6400, -200, 400, 300); //right wall spawn.mapRect(6700, -1800, 800, 2600); //right wall spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 100); //exit bump //place to hide spawn.mapRect(4650, -300, 1150, 50); spawn.mapRect(5750, -300, 50, 200); spawn.mapRect(5575, -100, 50, 125); spawn.mapRect(5300, -275, 50, 175); spawn.mapRect(5050, -100, 50, 150); spawn.mapRect(4850, -275, 50, 175); //??? level.difficultyIncrease(5) //30 is near max on hard //60 is near max on why m.addHealth(Infinity) // spawn.starter(1900, -500, 200) //big boy for (let i = 0; i < 10; ++i) spawn.launcher(1900, -500) // spawn.slashBoss(1900, -500) // spawn.launcherBoss(3200, -500) // spawn.laserTargetingBoss(1700, -500) // spawn.powerUpBoss(1900, -500) // spawn.powerUpBossBaby(3200, -500) // spawn.snakeBoss(1700, -500) // spawn.streamBoss(3200, -500) // spawn.pulsarBoss(1700, -500) // spawn.spawnerBossCulture(3200, -500) // spawn.grenadierBoss(1700, -500) // spawn.growBossCulture(3200, -500) // spawn.blinkBoss(1700, -500) // spawn.snakeSpitBoss(3200, -500) // spawn.laserBombingBoss(1700, -500) // spawn.launcherBoss(3200, -500) // spawn.blockBoss(1700, -500) // spawn.blinkBoss(3200, -500) // spawn.mantisBoss(1700, -500) // spawn.tetherBoss(1700, -500) //go to actual level? // spawn.revolutionBoss(1900, -500) // spawn.bomberBoss(1400, -500) // spawn.cellBossCulture(1600, -500) // spawn.shieldingBoss(1700, -500) // for (let i = 0; i < 10; ++i) spawn.bodyRect(1600 + 5, -500, 30, 40); // for (let i = 0; i < 5; i++) spawn.focuser(1900, -500) // spawn.pulsar(1900, -500) // spawn.shield(mob[mob.length - 1], 1900, -500, 1); // mob[mob.length - 1].isShielded = true // spawn.nodeGroup(1200, 0, "grenadier") // spawn.blinkBoss(1200, -500) // spawn.suckerBoss(2900, -500) // spawn.randomMob(1600, -500) }, reactor() { level.setPosToSpawn(-50, -800); //normal spawn spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); level.exit.x = 3000; level.exit.y = -35; spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 25); level.defaultZoom = 2000 simulation.zoomTransition(level.defaultZoom) document.body.style.backgroundColor = "#d0d5df" //"#d8dadf"; // powerUps.spawnStartingPowerUps(1475, -1175); // spawn.debris(750, -2200, 3700, 16); //16 debris per level spawn.mapRect(-1525, -2825, 1250, 4925); spawn.mapRect(-400, -2025, 625, 925); spawn.mapRect(-400, -750, 625, 1200); // spawn.mapVertex(200, 0, "-200 0 -100 -100 100 -100 200 0"); // spawn.bodyRect(225, -100, 100, 100, 0.5); // spawn.bodyRect(225, -200, 75, 100, 0.5); spawn.bodyRect(250, -70, 100, 70, 1); // spawn.bodyRect(-275, -850, 75, 100, 0.4); // spawn.bodyRect(1525, -100, 100, 100, 0.3); // spawn.bodyRect(2325, -50, 125, 50, 0.3); // spawn.bodyRect(2375, -100, 50, 50, 0.3); for (let i = 0; i < 3; ++i) powerUps.spawn(400 + 2000 * Math.random(), -25, "ammo"); spawn.mapRect(-425, 0, 4200, 2100); spawn.mapRect(175, -1250, 50, 300); spawn.mapRect(-475, -2825, 4250, 1025); // spawn.mapRect(1200, -1300, 600, 800); const a = 400 //side length const c = 100 //corner offset spawn.mapVertex(1487, -900, `${-a} ${-a+c} ${-a+c} ${-a} ${a-c} ${-a} ${a} ${-a+c} ${a} ${a-c} ${a-c} ${a} ${-a+c} ${a} ${-a} ${a-c}`); //square with edges cut off //exit spawn.mapRect(3300, -2825, 1125, 4925); spawn.mapRect(2750, -2150, 1025, 1775); spawn.mapRect(2750, -475, 50, 300); // spawn.bodyRect(1540, -1110, 300, 25, 0.9); // spawn.randomSmallMob(1300, -70); // spawn.randomMob(2650, -975, 0.8); // const doorIn = level.door(187, -450, 25, 250, 2) //x, y, width, height, distance, speed = 1 // doorIn.isClosing = false // level.custom = () => { // level.exit.drawAndCheck(); // // if (mob.length > 0) { // // doorIn.isClosing = true // // } else { // // doorIn.isClosing = false // // } // doorIn.isClosing = !(mob.length > 0) // doorIn.openClose(); const doorIn = level.door(187, -950, 25, 200, 190, 2) //x, y, width, height, distance, speed = 1 const doorOut = level.door(2762, -175, 25, 200, 190, 2) //x, y, width, height, distance, speed = 1 doorOut.isClosing = true let isDoorsLocked = false let isFightOver = false let isSpawnedBoss = false level.custom = () => { // player.force.y -= player.mass * simulation.g * 0.4; //float player if (isDoorsLocked) { if (!isFightOver && !(simulation.cycle % 120)) { //once a second let isFoundBoss = false for (let i = 0; i < mob.length; i++) { if (mob[i].isBoss) { isFoundBoss = true break } } if (!isFoundBoss) { isFightOver = true doorIn.isClosing = false doorOut.isClosing = false powerUps.spawnBossPowerUp(2900, -100) } } // if (mob.length > 0) { // doorIn.isClosing = true // doorOut.isClosing = true // } else if (!isFightOver) { // isFightOver = true // doorIn.isClosing = false // doorOut.isClosing = false // powerUps.spawnBossPowerUp(2900, -200) // } if (player.position.x < 0) { //if player gets trapped inside starting room open up again isDoorsLocked = false doorIn.isClosing = false } } else if (player.position.x > 225) { isDoorsLocked = true doorIn.isClosing = true doorOut.isClosing = true if (!isSpawnedBoss) { isSpawnedBoss = true if (Math.random() < 0.33) { for (let i = 0, len = Math.min(simulation.difficulty / 20, 6); i < len; ++i) spawn.bounceBoss(1487 + 200 * i, -1525, 80, false); } else if (Math.random() < 0.5) { for (let i = 0, len = Math.min(simulation.difficulty / 9, 8); i < len; ++i) spawn.sprayBoss(2400 - 150 * i, -225, 30, false) } else { for (let i = 0, len = Math.min(simulation.difficulty / 6, 10); i < len; ++i) spawn.mineBoss(1950, -250, 50, false); } // for (let i = 0, len = 3 + simulation.difficulty / 20; i < len; ++i) spawn.mantisBoss(1487 + 300 * i, -1525, 35, false) } } doorIn.openClose(); doorOut.openClose(); ctx.fillStyle = "#d5ebef" ctx.fillRect(2750, -375, 550, 375) level.enter.draw(); level.exit.drawAndCheck(); }; level.customTopLayer = () => { // if (isDoorsLocked) { // ctx.fillStyle = "#333" // ctx.fillRect(2800, -375, 500, 375); // } doorIn.draw(); doorOut.draw(); ctx.fillStyle = "rgba(0,0,0,0.05)" ctx.fillRect(-275, -1100, 500, 350); // ctx.fillStyle = "rgba(0,255,255,0.1)" // ctx.fillRect(2750, -375, 550, 375) }; // if (simulation.difficulty > 1) spawn.randomLevelBoss(2200, -1300); powerUps.addResearchToLevel() //needs to run after mobs are spawned }, template() { level.custom = () => { level.exit.drawAndCheck(); level.enter.draw(); }; level.customTopLayer = () => {}; level.setPosToSpawn(0, -50); //normal spawn level.exit.x = 1500; level.exit.y = -1875; spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); level.defaultZoom = 1800 simulation.zoomTransition(level.defaultZoom) document.body.style.backgroundColor = "#d8dadf"; // powerUps.spawnStartingPowerUps(1475, -1175); // spawn.debris(750, -2200, 3700, 16); //16 debris per level spawn.mapRect(-100, 0, 1000, 100); // spawn.bodyRect(1540, -1110, 300, 25, 0.9); // spawn.randomSmallMob(1300, -70); // spawn.randomMob(2650, -975, 0.8); // spawn.randomGroup(1700, -900, 0.4); // if (simulation.difficulty > 1) spawn.randomLevelBoss(2200, -1300); powerUps.addResearchToLevel() //needs to run after mobs are spawned }, final() { level.custom = () => { level.exit.drawAndCheck(); level.enter.draw(); }; level.customTopLayer = () => { ctx.fillStyle = "rgba(0,255,255,0.1)" ctx.fillRect(5400, -550, 300, 350) }; level.setPosToSpawn(0, -250); //normal spawn spawn.mapRect(5500, -330 + 20, 100, 20); //spawn this because the real exit is in the wrong spot spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); level.exit.x = 550000; level.exit.y = -330; level.defaultZoom = 2500 simulation.zoomTransition(level.defaultZoom) document.body.style.backgroundColor = "#ddd"; powerUps.spawn(1675, -50, "ammo"); powerUps.spawn(3350, -75, "ammo"); powerUps.spawn(3925, -50, "ammo"); powerUps.spawn(4250, -75, "ammo"); powerUps.spawn(4550, -75, "ammo"); powerUps.spawn(5025, -50, "ammo"); powerUps.spawn(4725, -50, "ammo"); powerUps.spawn(4975, -350, "ammo"); powerUps.spawn(5125, -350, "ammo"); powerUps.spawn(5075, -425, "ammo"); powerUps.spawn(5050, -400, "ammo"); powerUps.spawn(5075, -425, "ammo"); spawn.mapRect(-1950, 0, 8200, 1800); //ground spawn.mapRect(-1950, -1500, 1800, 1900); //left wall spawn.mapRect(-1950, -3300, 8200, 1800); //roof spawn.mapRect(-250, -200, 1000, 300); // shelf spawn.mapRect(-250, -1700, 1000, 1250); // shelf roof spawn.blockDoor(710, -210); spawn.finalBoss(3000, -750) spawn.mapRect(5400, -1700, 400, 1150); //right wall spawn.mapRect(5400, -300, 400, 400); //right wall spawn.mapRect(5700, -3300, 1800, 5100); //right wall spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 100); //exit bump spawn.mapRect(5425, -650, 375, 450); //blocking exit // spawn.secondaryBossChance(4800, -500) //no bonus bosses on final level if (simulation.isHorizontalFlipped) { //flip the map horizontally level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit level.setPosToSpawn(0, -250); level.custom = () => { level.exit.drawAndCheck(); level.enter.draw(); }; level.customTopLayer = () => { ctx.fillStyle = "rgba(0,255,255,0.1)" ctx.fillRect(-5400 - 300, -550, 300, 350) }; } }, gauntlet() { level.custom = () => { level.exit.drawAndCheck(); level.enter.draw(); }; level.customTopLayer = () => { ctx.fillStyle = "rgba(0,255,255,0.1)" ctx.fillRect(6400, -550, 300, 350) ctx.fillStyle = "rgba(0,0,0,0.1)" ctx.fillRect(-175, -975, 900, 575) }; level.setPosToSpawn(0, -475); //normal spawn spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); level.exit.x = 6500; level.exit.y = -230; level.defaultZoom = 1500 simulation.zoomTransition(level.defaultZoom) document.body.style.backgroundColor = "#ddd"; // spawn.mapRect(-300, -1050, 300, 200); // Matter.Body.setAngle(map[map.length - 1], -Math.PI / 4) spawn.mapRect(-950, 0, 8200, 800); //ground spawn.mapRect(-950, -1200, 800, 1400); //left wall spawn.mapRect(-950, -1800, 8200, 800); //roof spawn.mapRect(175, -700, 575, 950); spawn.mapRect(-250, -425, 600, 650); spawn.mapRect(-250, -1200, 1000, 250); // shelf roof powerUps.spawnStartingPowerUps(600, -800); spawn.blockDoor(710, -710); spawn[spawn.pickList[0]](1500, -200, 150 + Math.random() * 30); spawn.mapRect(2500, -1200, 200, 750); //right wall spawn.blockDoor(2585, -210) spawn.mapRect(2500, -200, 200, 300); //right wall spawn.nodeGroup(3500, -200, spawn.allowedGroupList[Math.floor(Math.random() * spawn.allowedGroupList.length)]); spawn.mapRect(4500, -1200, 200, 750); //right wall spawn.blockDoor(4585, -210) spawn.mapRect(4500, -200, 200, 300); //right wall spawn.lineGroup(5000, -200, spawn.allowedGroupList[Math.floor(Math.random() * spawn.allowedGroupList.length)]); spawn.mapRect(6400, -1200, 400, 750); //right wall spawn.mapRect(6400, -200, 400, 300); //right wall spawn.mapRect(6700, -1800, 800, 2600); //right wall spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 100); //exit bump for (let i = 0; i < 3; ++i) { if (simulation.difficulty * Math.random() > 15 * i) spawn.randomGroup(2000 + 500 * (Math.random() - 0.5), -800 + 200 * (Math.random() - 0.5), Infinity); if (simulation.difficulty * Math.random() > 10 * i) spawn.randomGroup(3500 + 500 * (Math.random() - 0.5), -800 + 200 * (Math.random() - 0.5), Infinity); if (simulation.difficulty * Math.random() > 7 * i) spawn.randomGroup(5000 + 500 * (Math.random() - 0.5), -800 + 200 * (Math.random() - 0.5), Infinity); } powerUps.addResearchToLevel() //needs to run after mobs are spawned spawn.secondaryBossChance(4125, -350) if (simulation.isHorizontalFlipped) { //flip the map horizontally level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit level.setPosToSpawn(0, -475); level.custom = () => { level.exit.drawAndCheck(); level.enter.draw(); }; level.customTopLayer = () => { ctx.fillStyle = "rgba(0,255,255,0.1)" ctx.fillRect(-6400 - 300, -550, 300, 350) ctx.fillStyle = "rgba(0,0,0,0.1)" ctx.fillRect(175 - 900, -975, 900, 575) }; } }, intro() { if (level.levelsCleared === 0) { //if this is the 1st level of the game //wait to spawn power ups until unpaused //power ups don't spawn in experiment mode, so they don't get removed at the start of experiment mode function cycle() { if (simulation.cycle > 10) { // powerUps.spawn(2500, -50, "research", false); powerUps.spawn(2095 + 15 * (Math.random() - 0.5), -2070, "research", false); powerUps.spawn(2095 + 15 * (Math.random() - 0.5), -2070 - 25, "heal", false); powerUps.spawn(2095 + 15 * (Math.random() - 0.5), -2070 - 75, "heal", false); powerUps.spawnStartingPowerUps(2095 + 15 * (Math.random() - 0.5), -2070 - 125); } else { requestAnimationFrame(cycle); } } requestAnimationFrame(cycle); if (localSettings.levelsClearedLastGame < 3) { if (!simulation.isCheating && !m.isShipMode && !build.isExperimentRun) { spawn.wireFoot(); spawn.wireFootLeft(); spawn.wireKnee(); spawn.wireKneeLeft(); spawn.wireHead(); // for (let i = 0; i < 3; i++) powerUps.spawn(2095, -1220 - 50 * i, "tech", false); //unavailable tech spawns // spawn.mapRect(2000, -1025, 200, 25); } } else if (!build.isExperimentRun) { simulation.trails() //bonus power ups for clearing runs in the last game if (!simulation.isCheating && localSettings.levelsClearedLastGame > 1) { for (let i = 0; i < localSettings.levelsClearedLastGame / 3; i++) powerUps.spawn(2095 + 2 * Math.random(), -1270 - 50 * i, "tech", false); //spawn a tech for levels cleared in last game simulation.makeTextLog(`for (let i = 0; i < localSettings.levelsClearedLastGame / 3; i++)`); simulation.makeTextLog(`{ powerUps.spawn(m.pos.x, m.pos.y, "tech") //simulation superposition}`); localSettings.levelsClearedLastGame = 0 //after getting bonus power ups reset run history if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage } } spawn.mapRect(2025, 0, 150, 50); //lid to floor hole } else { for (let i = 0; i < 60; i++) { setTimeout(() => { spawn.sneaker(2100, -1500 - 50 * i); }, 2000 + 500 * i); } } const wires = new Path2D() //pre-draw the complex lighting path to save processing wires.moveTo(-150, -275) wires.lineTo(80, -275) wires.lineTo(80, -1000) wires.moveTo(-150, -265) wires.lineTo(90, -265) wires.lineTo(90, -1000) wires.moveTo(-150, -255) wires.lineTo(100, -255) wires.lineTo(100, -1000) wires.moveTo(-150, -245) wires.lineTo(1145, -245) wires.lineTo(1145, 0) wires.moveTo(-150, -235) wires.lineTo(1135, -235) wires.lineTo(1135, 0) wires.moveTo(-150, -225) wires.lineTo(1125, -225) wires.lineTo(1125, 0) wires.moveTo(-150, -215) wires.lineTo(460, -215) wires.lineTo(460, 0) wires.moveTo(-150, -205) wires.lineTo(450, -205) wires.lineTo(450, 0) wires.moveTo(-150, -195) wires.lineTo(440, -195) wires.lineTo(440, 0) wires.moveTo(1155, 0) wires.lineTo(1155, -450) wires.lineTo(1000, -450) wires.lineTo(1000, -1000) wires.moveTo(1165, 0) wires.lineTo(1165, -460) wires.lineTo(1010, -460) wires.lineTo(1010, -1000) wires.moveTo(1175, 0) wires.lineTo(1175, -470) wires.lineTo(1020, -470) wires.lineTo(1020, -1000) wires.moveTo(1185, 0) wires.lineTo(1185, -480) wires.lineTo(1030, -480) wires.lineTo(1030, -1000) wires.moveTo(1195, 0) wires.lineTo(1195, -490) wires.lineTo(1040, -490) wires.lineTo(1040, -1000) wires.moveTo(1625, -1000) wires.lineTo(1625, 0) wires.moveTo(1635, -1000) wires.lineTo(1635, 0) wires.moveTo(1645, -1000) wires.lineTo(1645, 0) wires.moveTo(1655, -1000) wires.lineTo(1655, 0) wires.moveTo(1665, -1000) wires.lineTo(1665, 0) wires.moveTo(1675, -465) wires.lineTo(2325, -465) wires.lineTo(2325, 0) wires.moveTo(1675, -455) wires.lineTo(2315, -455) wires.lineTo(2315, 0) wires.moveTo(1675, -445) wires.lineTo(2305, -445) wires.lineTo(2305, 0) wires.moveTo(1675, -435) wires.lineTo(2295, -435) wires.lineTo(2295, 0) wires.moveTo(2335, 0) wires.lineTo(2335, -710) wires.lineTo(2600, -710) wires.moveTo(2345, 0) wires.lineTo(2345, -700) wires.lineTo(2600, -700) wires.moveTo(2355, 0) wires.lineTo(2355, -690) wires.lineTo(2600, -690) level.custom = () => { //push around power ups stuck in the tube wall if (!(simulation.cycle % 30)) { for (let i = 0, len = powerUp.length; i < len; i++) { if (powerUp[i].position.y < -1000) powerUp[i].force.x += 0.01 * (Math.random() - 0.5) * powerUp[i].mass } } //draw binary number const binary = (localSettings.runCount >>> 0).toString(2) const height = 20 const width = 8 const yOff = -40 //-580 let xOff = -130 //2622 ctx.strokeStyle = "#bff" ctx.lineWidth = 1.5; ctx.beginPath() for (let i = 0; i < binary.length; i++) { if (binary[i] === "0") { ctx.moveTo(xOff, yOff) ctx.lineTo(xOff, yOff + height) ctx.lineTo(xOff + width, yOff + height) ctx.lineTo(xOff + width, yOff) ctx.lineTo(xOff, yOff) xOff += 10 + width } else { ctx.moveTo(xOff, yOff) ctx.lineTo(xOff, yOff + height) xOff += 10 } } ctx.stroke(); ctx.beginPath() ctx.strokeStyle = "#ccc" ctx.lineWidth = 5; ctx.stroke(wires); //squares that look like they keep the wires in place ctx.beginPath() ctx.rect(1600, -500, 90, 100) ctx.rect(-55, -285, 12, 100) ctx.rect(1100, -497, 8, 54) ctx.rect(2285, -200, 80, 10) ctx.rect(1110, -70, 100, 10) ctx.fillStyle = "#ccc" ctx.fill() //power up dispenser // ctx.beginPath() // for (let i = 2; i < 10; i++) { // ctx.moveTo(2000, -100 * i) // ctx.lineTo(2080, -100 * i) // } // ctx.strokeStyle = "#ddd" // ctx.lineWidth = 5; // ctx.stroke(); // ctx.beginPath() // for (let i = 2; i < 10; i++) { // ctx.arc(2040, -100 * i, 30, 0, 2 * Math.PI); // ctx.moveTo(2040, -100 * i) // } // ctx.fillStyle = "rgba(0,0,0,0.3)" // ctx.fill() // ctx.fillStyle = "rgba(240,255,255,0.5)" // ctx.fillRect(2000, -1000, 80, 700) //exit room ctx.fillStyle = "#f2f2f2" ctx.fillRect(2600, -600, 400, 300) // level.enter.draw(); level.exit.drawAndCheck(); }; level.customTopLayer = () => { //exit room glow ctx.fillStyle = "rgba(0,255,255,0.05)" ctx.fillRect(2600, -600, 400, 300) //draw shade for ceiling tech ctx.fillStyle = "rgba(68, 68, 68,0.95)" ctx.fillRect(2030, -2800, 150, 1800); ctx.fillStyle = "rgba(68, 68, 68,0.95)" ctx.fillRect(2030, 0, 150, 1800); }; 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 simulation.zoomScale = 1000 //1400 is normal level.defaultZoom = 1600 simulation.zoomTransition(level.defaultZoom, 1) document.body.style.backgroundColor = "#e1e1e1"; spawn.mapRect(-2750, -2800, 2600, 4600); //left wall spawn.mapRect(3000, -2800, 2600, 4600); //right wall // spawn.mapRect(-250, 0, 3600, 1800); //ground spawn.mapRect(-250, 0, 2300, 1800); //split roof spawn.mapRect(2150, 0, 1200, 1800); //split roof spawn.mapRect(2025, -3, 25, 15); //lip on power up chamber spawn.mapRect(2150, -3, 25, 15); //lip on power up chamber // spawn.mapRect(-250, -2800, 3600, 1800); //roof spawn.mapRect(-250, -2800, 2300, 1800); //split roof map[map.length - 1].friction = 0 map[map.length - 1].frictionStatic = 0 spawn.mapRect(2150, -2800, 1200, 1800); //split roof map[map.length - 1].friction = 0 map[map.length - 1].frictionStatic = 0 spawn.mapRect(2025, -1010, 25, 13); //lip on power up chamber spawn.mapRect(2150, -1010, 25, 13); //lip on power up chamber spawn.mapRect(2600, -300, 500, 500); //exit shelf spawn.mapRect(2600, -1200, 500, 600); //exit roof spawn.mapRect(-95, -1100, 80, 110); //wire source spawn.mapRect(410, -10, 90, 20); //small platform for player spawn.bodyRect(2425, -120, 70, 50); spawn.bodyRect(2400, -100, 100, 60); spawn.bodyRect(2500, -150, 100, 150); //exit step }, reservoir() { level.exit.x = 1700; level.exit.y = -4510; spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 25); level.setPosToSpawn(-500, 850); //normal spawn spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); level.defaultZoom = 2300 simulation.zoomTransition(level.defaultZoom) document.body.style.backgroundColor = "#d8dadf"; powerUps.spawnStartingPowerUps(-575, -2925) // spawn.debris(750, -2200, 3700, 16); //16 debris per level //no debris? //walls spawn.mapRect(-3500, -5000, 1500, 6500); spawn.mapRect(2000, -5000, 1500, 6500); spawn.mapRect(-2500, 1100, 5000, 400); //slime floor spawn.mapRect(-3500, -5475, 7000, 600); //top spawn.mapRect(-1925, -4900, 175, 375); //pipe spawn.mapRect(-1950, -4550, 225, 25); //pipe //top floor exit spawn.mapRect(1475, -4900, 50, 250); spawn.mapRect(1400, -4475, 650, 50); // ground spawn.mapVertex(-687, 1060, "700 0 -700 0 -450 -300 450 -300"); //left base spawn.mapVertex(863, 1060, "700 0 -700 0 -450 -300 450 -300"); //right base //entrance spawn.mapRect(-730, 525, 475, 50); spawn.mapRect(-730, 550, 50, 150); spawn.mapRect(-305, 550, 50, 500); spawn.bodyRect(-717, 700, 25, 100); //door spawn.bodyRect(-717, 800, 25, 100); //door //1st floor //left spawn.mapVertex(-1125 + 437, -50, "490 0 350 80 -350 80 -490 0 -350 -80 350 -80"); spawn.mapRect(-1225, -100, 1070, 100); if (Math.random() < 0.33) { spawn.mapVertex(-687, -1000, "-100 -300 0 -350 100 -300 100 300 0 350 -100 300"); } else if (Math.random() < 0.5) { spawn.mapVertex(-687, -1000, "-150 -450 0 -525 150 -450 150 450 0 525 -150 450"); } else { spawn.mapVertex(-687, -700, "-150 0 150 0 150 450 0 525 -150 450"); } //right spawn.mapVertex(425 + 437, -50, "490 0 350 80 -350 80 -490 0 -350 -80 350 -80"); spawn.mapRect(325, -100, 1070, 100); // spawn.mapRect(225, 675, 375, 25); // spawn.mapRect(675, 450, 375, 25); // spawn.mapRect(1125, 225, 375, 25); spawn.mapRect(175, 675, 425, 25); spawn.mapRect(1125, 225, 425, 25); spawn.mapRect(650, 450, 425, 25); if (Math.random() < 0.33) { spawn.mapVertex(855, -1000, "-100 -300 0 -350 100 -300 100 300 0 350 -100 300"); } else if (Math.random() < 0.5) { spawn.mapVertex(855, -1000, "-150 -450 0 -525 150 -450 150 450 0 525 -150 450"); } else { spawn.mapVertex(855, -700, "-150 0 150 0 150 450 0 525 -150 450"); } //2nd floor spawn.mapVertex(855, -1936, "-612 50 0 100 612 50 612 -50 -612 -50"); spawn.mapVertex(-687, -1936, "-612 50 0 100 612 50 612 -50 -612 -50"); //2nd floor right building // spawn.mapRect(550, -3050, 600, 175); spawn.mapRect(550, -3050, 600, 75); spawn.bodyRect(-125, -2025, 475, 25); //2nd floor left building // if (Math.random() > 0.5) { // spawn.mapRect(-925, -2350, 675, 200); // } else { // } spawn.mapRect(-925, -2350, 675, 50); spawn.mapRect(-825, -2825, 425, 50); // spawn.mapRect(-825, -2825, 425, 275); spawn.mapRect(-450, -3125, 50, 350); spawn.mapRect(-750, -3150, 350, 50); spawn.mapRect(-650, -3400, 250, 300); spawn.mapRect(-650, -3675, 200, 50); spawn.bodyRect(-375, -2150, 100, 150, 0.2); //2nd floor left pillar spawn.mapRect(-1400, -2625, 325, 25); spawn.mapRect(-1450, -3225, 425, 25); // spawn.mapRect(-1500, -3825, 525, 25); spawn.mapRect(-1512.5, -3825, 550, 25); // spawn.mapRect(-1400, -3225, 325, 25); // spawn.mapRect(-1400, -3825, 325, 25); spawn.randomMob(1000, -275, 0.2); spawn.randomMob(950, -1725, 0.1); spawn.randomMob(-725, -1775, 0.1); spawn.randomMob(-200, -2075, 0); spawn.randomMob(375, -2125, 0); spawn.randomMob(1025, -3200, 0); spawn.randomMob(-550, -3500, 0); spawn.randomMob(-700, -2450, -0.1); spawn.randomMob(-1175, -2775, -0.1); spawn.randomMob(-525, -3750, -0.2); spawn.randomMob(1350, -2075, -0.3); spawn.randomMob(1775, 1000, -0.4); spawn.randomSmallMob(-575, -2925); spawn.randomGroup(-400, -4400, 0); if (simulation.difficulty > 1) { spawn.randomLevelBoss(825, -3500); spawn.secondaryBossChance(75, -1350) } powerUps.addResearchToLevel() //needs to run after mobs are spawned const slime = level.hazard(-2000, -5000, 4000, 6060); // hazard(x, y, width, height, damage = 0.003) slime.height -= slime.maxHeight - 60 //start slime at zero slime.min.y += slime.maxHeight slime.max.y = slime.min.y + slime.height const elevator1 = level.elevator(-1625, -90, 310, 800, -2000, 0.0025, { up: 0.1, down: 0.2 }) //x, y, width, height, maxHeight, force = 0.003, friction = { up: 0.01, down: 0.2 }) { const elevator2 = level.elevator(1175, -3050, 200, 250, -4475, 0.0025, { up: 0.12, down: 0.2 }) //x, y, width, height, maxHeight, force = 0.003, friction = { up: 0.01, down: 0.2 }) { let waterFallWidth = 0 let waterFallX = 0 let waterFallSmoothX = 0 let isWaterfallFilling = false const riseRate = 0.25 + Math.min(1, simulation.difficulty * 0.01) const spinnerArray = [] // level.difficultyIncrease(30) //30 is near max on hard //60 is near max on why // m.immuneCycle = Infinity //you can't take damage // simulation.isHorizontalFlipped = true if (simulation.isHorizontalFlipped) { //flip the map horizontally spawn.mapVertex(584, -2500, "0 0 300 0 150 600 0 600"); spawn.mapVertex(1116, -2500, "0 0 300 0 300 600 150 600"); spawn.bodyRect(-200, -125, 625, 25); level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit elevator1.holdX = -elevator1.holdX // flip the elevator horizontally elevator2.holdX = -elevator2.holdX // flip the elevator horizontally spinnerArray.push(level.spinner(-110, -3325, 45, 600, 0.003, 0, 0, 0.01)) // spinner(x, y, width, height, density = 0.001, angle = 0, frictionAir = 0.001, angularVelocity = 0) { const boost1 = level.boost(-900, -2000, 790) level.setPosToSpawn(500, 850); //normal spawn level.custom = () => { ctx.fillStyle = "#c0c3c9" ///!!!!!!!!!! for flipped x: newX = -oldX - width ctx.fillRect(1468, -1975, 2, 1915) //elevator track ctx.fillRect(-1274, -4460, 2, 1425) //elevator track ctx.fillRect(1225, -3825, 25, 1850); //small pillar background ctx.fillStyle = "#d0d4d6" ctx.fillRect(275, -1925, 825, 2925) //large pillar background ctx.fillRect(-1275, -1925, 825, 2925) //large pillar background ctx.fillStyle = "#cff" //exit ctx.fillRect(-2000, -4900, 525, 425) level.exit.drawAndCheck(); level.enter.draw(); }; level.customTopLayer = () => { boost1.query(); elevator1.move(); elevator2.move(); ctx.fillStyle = "#233" ctx.beginPath(); //central dot on spinners ctx.arc(spinnerArray[0].pointA.x, spinnerArray[0].pointA.y, 9, 0, 2 * Math.PI); for (let i = 0, len = spinnerArray.length; i < len; i++) { ctx.moveTo(spinnerArray[i].pointA.x, spinnerArray[i].pointA.y) ctx.arc(spinnerArray[i].pointA.x, spinnerArray[i].pointA.y, 9, 0, 2 * Math.PI); } ctx.fill(); //shadow ctx.fillStyle = "rgba(0,10,30,0.1)" ctx.fillRect(-1150, -3000, 600, 1025); ctx.fillRect(450, -3100, 300, 275); ctx.fillRect(450, -3625, 200, 225); ctx.fillRect(400, -2775, 425, 450); ctx.fillRect(250, -2300, 675, 300); slime.query(); if (isWaterfallFilling) { if (slime.height < 5500) { //draw slime fill ctx.fillStyle = `hsla(160, 100%, 43%,${0.3+0.07*Math.random()})` ctx.fillRect(waterFallX, -5050, waterFallWidth, 6175 - slime.height) if (!m.isBodiesAsleep) { waterFallWidth = 0.98 * waterFallWidth + 4.7 * Math.random() waterFallSmoothX = 0.98 * waterFallSmoothX + 3.5 * Math.random() waterFallX = 1857 - waterFallSmoothX ctx.fillRect(waterFallX + waterFallWidth * Math.random(), -5050, 4, 6175 - slime.height) //push player down if they go under waterfall if (player.position.x > waterFallX && player.position.x < waterFallX + waterFallWidth && player.position.y < slime.height) { Matter.Body.setVelocity(player, { x: player.velocity.x, y: player.velocity.y + 2 }); } } slime.levelRise(riseRate) } } else if (Vector.magnitudeSquared(Vector.sub(player.position, level.enter)) > 100000) { isWaterfallFilling = true } }; } else { //not flipped spawn.mapVertex(1116, -2500, "0 0 300 0 150 600 0 600"); spawn.mapVertex(584, -2500, "0 0 300 0 300 600 150 600"); if (Math.random() < 0.33) { spinnerArray.push(level.spinner(65, -300, 40, 450, 0.003, Math.PI / 2)) } else { spinnerArray.push(level.spinner(65, -500, 40, 500, 0.003, 0, 0, -0.015)) // spinner(x, y, width, height, density = 0.001, angle = 0, frictionAir = 0.001, angularVelocity = 0) { const r = 250 const hexagon = `${r} 0 ${r * Math.cos(5.236)} ${r * Math.sin(5.236)} ${r * Math.cos(4.189)} ${r * Math.sin(4.189)} ${-r} 0 ${r * Math.cos(2.0944)} ${r * Math.sin(2.0944)} ${r * Math.cos(1.0472)} ${r * Math.sin(1.0472)} ` Matter.Body.setVertices(spinnerArray[spinnerArray.length - 1].bodyB, Vertices.fromPath(hexagon)) } spinnerArray.push(level.spinner(50, -3325, 45, 600, 0.003, 0, 0, 0.01)) // spinner(x, y, width, height, density = 0.001, angle = 0, frictionAir = 0.001, angularVelocity = 0) { if (Math.random() < 0.5) { const r = 200 const hexagon = `${r} 0 ${r * Math.cos(5.236)} ${r * Math.sin(5.236)} ${r * Math.cos(4.189)} ${r * Math.sin(4.189)} ${-r} 0 ${r * Math.cos(2.0944)} ${r * Math.sin(2.0944)} ${r * Math.cos(1.0472)} ${r * Math.sin(1.0472)} ` Matter.Body.setVertices(spinnerArray[spinnerArray.length - 1].bodyB, Vertices.fromPath(hexagon)) } const boost1 = level.boost(800, -2000, 790) level.custom = () => { ctx.fillStyle = "#c0c3c9" ctx.fillRect(-1470, -1975, 2, 1915) //elevator track ctx.fillRect(1276, -4460, 2, 1425) //elevator track ctx.fillRect(-1250, -3825, 25, 1850); //small pillar background ctx.fillStyle = "#d0d4d6" ctx.fillRect(-1100, -1925, 825, 2925) //large pillar background ctx.fillRect(450, -1925, 825, 2925) //large pillar background ctx.fillStyle = "#cff" //exit ctx.fillRect(1475, -4900, 525, 425) level.exit.drawAndCheck(); level.enter.draw(); }; level.customTopLayer = () => { boost1.query(); elevator1.move(); elevator2.move(); ctx.fillStyle = "#233" ctx.beginPath(); //central dot on spinners ctx.arc(spinnerArray[0].pointA.x, spinnerArray[0].pointA.y, 9, 0, 2 * Math.PI); for (let i = 0, len = spinnerArray.length; i < len; i++) { ctx.moveTo(spinnerArray[i].pointA.x, spinnerArray[i].pointA.y) ctx.arc(spinnerArray[i].pointA.x, spinnerArray[i].pointA.y, 9, 0, 2 * Math.PI); } ctx.fill(); //shadow ctx.fillStyle = "rgba(0,10,30,0.1)" ctx.fillRect(550, -3000, 600, 1025); ctx.fillRect(-750, -3100, 300, 275); ctx.fillRect(-650, -3625, 200, 225); ctx.fillRect(-825, -2775, 425, 450); ctx.fillRect(-925, -2300, 675, 300); slime.query(); if (isWaterfallFilling) { if (slime.height < 5500) { //draw slime fill ctx.fillStyle = `hsla(160, 100%, 43%,${0.3+0.07*Math.random()})` ctx.fillRect(waterFallX, -5050, waterFallWidth, 6175 - slime.height) if (!m.isBodiesAsleep) { waterFallWidth = 0.98 * waterFallWidth + 4.7 * Math.random() waterFallSmoothX = 0.98 * waterFallSmoothX + 3.5 * Math.random() waterFallX = waterFallSmoothX - 1985 ctx.fillRect(waterFallX + waterFallWidth * Math.random(), -5050, 4, 6175 - slime.height) //push player down if they go under waterfall if (player.position.x > waterFallX && player.position.x < waterFallX + waterFallWidth && player.position.y < slime.height) { Matter.Body.setVelocity(player, { x: player.velocity.x, y: player.velocity.y + 2 }); } } slime.levelRise(riseRate) } } else if (Vector.magnitudeSquared(Vector.sub(player.position, level.enter)) > 100000) { isWaterfallFilling = true } }; } }, pavilion() { const vanish = [] level.exit.x = -850; level.exit.y = -1485; spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 25); level.setPosToSpawn(-900, 225); //normal spawn spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); level.defaultZoom = 1500 simulation.zoomTransition(level.defaultZoom) document.body.style.backgroundColor = "#dcdcde"; spawn.debris(-150, -775, 1425, 3); //16 debris per level spawn.debris(1525, -25, 950, 3); //16 debris per level spawn.debris(-650, -2100, 575, 2); //16 debris per level //bottom floor //entrance spawn.mapRect(-200, -750, 1500, 100); spawn.mapRect(-575, 0, 2150, 500); // spawn.mapRect(-1275, 275, 875, 225); spawn.mapRect(-1275, 275, 3975, 225); spawn.mapRect(-1050, 0, 325, 50); spawn.mapRect(-775, 0, 50, 140); vanish.push(level.vanish(-725, 13, 150, 25)) spawn.mapRect(-200, -750, 100, 600); // spawn.mapRect(1200, -750, 100, 600); vanish.push(level.vanish(-350, -225, 150, 225)) vanish.push(level.vanish(-350, -450, 150, 223)) spawn.mapRect(2475, -1800, 250, 2300); spawn.mapRect(1200, -750, 100, 450); spawn.mapRect(1200, -375, 250, 75); powerUps.spawnStartingPowerUps(550, -100); spawn.mapRect(125, -12, 850, 50); spawn.mapRect(175, -25, 750, 50); spawn.bodyRect(1350, -175, 150, 175, 0.5); spawn.bodyRect(1350, -600, 125, 225, 0.2); //middle floor spawn.bodyRect(215, -1175, 100, 100, 0.3); spawn.mapRect(-1300, -1800, 250, 2300); // spawn.mapRect(-1300, -2075, 250, 2575); if (Math.random() < 0.5) { spawn.mapRect(500, -1350, 525, 425); spawn.mapRect(25, -1050, 300, 198); } else { spawn.mapRect(500, -1350, 525, 497); spawn.mapRect(25, -1050, 300, 150); } if (Math.random() < 0.5) { vanish.push(level.vanish(400, -1600, 175, 25)) vanish.push(level.vanish(950, -1600, 175, 25)) } else { vanish.push(level.vanish(550, -1575, 50, 225)) vanish.push(level.vanish(925, -1575, 50, 225)) } // vanish.push(level.vanish(575, -1575, 375, 225)) spawn.bodyRect(225, -850, 50, 100, 0.4); spawn.mapRect(600, -1800, 325, 225); spawn.mapRect(1900, -1500, 325, 25); spawn.bodyRect(1050, -1825, 250, 20, 0.2); if (Math.random() < 0.5) { vanish.push(level.vanish(1400, -1000, 200, 25)) vanish.push(level.vanish(1625, -1250, 200, 25)) } else { vanish.push(level.vanish(1400, -1075, 175, 175)) vanish.push(level.vanish(1575, -1250, 175, 175)) } vanish.push(level.vanish(1125, -1800, 625, 25)) // vanish.push(level.vanish(1500, -1800, 225, 25)) vanish.push(level.vanish(-50, -1800, 450, 25)) //exit spawn.mapRect(-1050, -1450, 700, 25); spawn.mapRect(-1050, -1800, 525, 25); spawn.mapRect(-550, -1800, 25, 200); spawn.randomMob(-1175, -1975, -0.4); spawn.randomMob(275, -1500, -0.3); spawn.randomMob(700, -1875, -0.2); spawn.randomMob(2000, -800, -0.2); spawn.randomMob(2600, -1850, 0); spawn.randomMob(1425, -525, 0.1); spawn.randomMob(2025, -1600, 0.3); spawn.randomMob(1625, -1875, 0.3); spawn.randomMob(-150, -1975, 0.4); spawn.randomSmallMob(900, -825); spawn.randomSmallMob(1050, -50); if (simulation.difficulty > 1) { spawn.randomGroup(750, -2150, -0.8) spawn.randomLevelBoss(2050, -2025) spawn.secondaryBossChance(100, -1500) } powerUps.addResearchToLevel() //needs to run after mobs are spawned if (simulation.isHorizontalFlipped) { //flip the map horizontally level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit level.setPosToSpawn(900, 225); //normal spawn level.custom = () => { ctx.fillStyle = "#d0d3d9" ctx.fillRect(-2500, -1800, 3575, 2100); ctx.fillStyle = "#c0c3c9" ctx.fillRect(-2075, -1475, 25, 1800); ctx.fillStyle = "#cff" //exit ctx.fillRect(550, -1800, 525, 350) level.exit.drawAndCheck(); level.enter.draw(); }; level.customTopLayer = () => { //shadow ctx.fillStyle = "rgba(0,10,30,0.1)" ctx.fillRect(-1450, -300, 150, 325); ctx.fillRect(-1300, -650, 1500, 650) ctx.fillRect(725, 50, 325, 225) ctx.fillRect(-325, -950, 300, 225) ctx.fillRect(-1025, -1000, 525, 275); ctx.fillRect(-925, -1600, 325, 275); for (let i = 0, len = vanish.length; i < len; i++) vanish[i].query() }; } else { level.custom = () => { ctx.fillStyle = "#d0d3d9" ctx.fillRect(-1075, -1800, 3575, 2100); ctx.fillStyle = "#c0c3c9" ctx.fillRect(2050, -1475, 25, 1800); ctx.fillStyle = "#cff" //exit ctx.fillRect(-1050, -1800, 525, 350) level.exit.drawAndCheck(); level.enter.draw(); }; level.customTopLayer = () => { //shadow ctx.fillStyle = "rgba(0,10,30,0.1)" ctx.fillRect(1300, -300, 150, 325); ctx.fillRect(-200, -675, 1500, 700) ctx.fillRect(500, -950, 525, 225); ctx.fillRect(600, -1600, 325, 275); ctx.fillRect(-1050, 50, 325, 225) ctx.fillRect(25, -950, 300, 225) for (let i = 0, len = vanish.length; i < len; i++) vanish[i].query() }; } }, testChamber() { level.setPosToSpawn(0, -50); //lower start level.exit.y = level.enter.y - 550; spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); level.exit.x = level.enter.x; spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20); level.defaultZoom = 2200 simulation.zoomTransition(level.defaultZoom) document.body.style.backgroundColor = "#d5d5d5"; spawn.mapRect(0, -1955, 175, 30); const removeIndex1 = map.length - 1 //so much work to catch blocks caught at the bottom of the vertical portals spawn.mapRect(1225, -1955, 175, 30); const removeIndex2 = map.length - 1 //so much work to catch blocks caught at the bottom of the vertical portals let portal, portal2, portal3 const hazard = level.hazard((simulation.isHorizontalFlipped ? -350 - 700 : 350), -2025, 700, 10, 0.4) //laser spawn.mapRect(340, -2032.5, 20, 25); //laser nose const hazard2 = level.hazard((simulation.isHorizontalFlipped ? -1775 - 150 : 1775), -2550, 150, 10, 0.4) //laser spawn.mapRect(1920, -2557.5, 20, 25); //laser nose const button = level.button(2100, -2600) const buttonDoor = level.button(600, -550) const door = level.door(312, -750, 25, 190, 185) level.custom = () => { if (!(m.cycle % 60)) { //so much work to catch blocks caught at the bottom of the vertical portals let touching = Matter.Query.collides(map[removeIndex1], body) if (touching.length) { Matter.Composite.remove(engine.world, touching[0].bodyB); for (let i = 0, len = body.length; i < len; i++) { if (body[i].id === touching[0].bodyB.id) { body.splice(i, 1); break } } } touching = Matter.Query.collides(map[removeIndex2], body) if (touching.length) { Matter.Composite.remove(engine.world, touching[0].bodyB); for (let i = 0, len = body.length; i < len; i++) { if (body[i].id === touching[0].bodyB.id) { body.splice(i, 1); break } } } } buttonDoor.query(); buttonDoor.draw(); if (buttonDoor.isUp) { door.isClosing = true } else { door.isClosing = false } door.openClose(); portal[2].query() portal[3].query() portal2[2].query() portal2[3].query() portal3[2].query() portal3[3].query() if (button.isUp) { hazard.isOn = false; hazard2.isOn = false; } else { hazard.isOn = true; hazard2.isOn = true; } button.query(); button.draw(); ctx.fillStyle = "#d4f4f4" ctx.fillRect(-300, -1000, 650, 500) level.exit.drawAndCheck(); level.enter.draw(); }; level.customTopLayer = () => { door.draw(); hazard.opticalQuery(); hazard2.opticalQuery(); portal[0].draw(); portal[1].draw(); portal[2].draw(); portal[3].draw(); portal2[0].draw(); portal2[1].draw(); portal2[2].draw(); portal2[3].draw(); portal3[0].draw(); portal3[1].draw(); portal3[2].draw(); portal3[3].draw(); }; powerUps.spawnStartingPowerUps(1875, -3075); const powerUpPos = shuffle([{ //no debris on this level but 2 random spawn instead x: -150, y: -1775 }, { x: 2400, y: -2650 }, { x: -175, y: -1375 }, { x: 1325, y: -150 }]); powerUps.chooseRandomPowerUp(powerUpPos[0].x, powerUpPos[0].y); powerUps.chooseRandomPowerUp(powerUpPos[1].x, powerUpPos[1].y); //outer wall spawn.mapRect(2500, -3700, 1200, 3800); //right map wall spawn.mapRect(-1400, -3800, 1100, 3900); //left map wall spawn.mapRect(-1400, -4800, 5100, 1200); //map ceiling spawn.mapRect(-1400, 0, 5100, 1200); //floor //lower entrance /exit spawn.mapRect(300, -375, 50, 225); spawn.bodyRect(312, -150, 25, 140); spawn.mapRect(300, -10, 50, 50); spawn.mapVertex(1555, 0, "625 0 75 0 200 -100 500 -100"); //entrance ramp //upper entrance / exit spawn.mapRect(-400, -1050, 750, 50); spawn.mapRect(300, -1050, 50, 300); // spawn.bodyRect(312, -750, 25, 190); spawn.mapRect(300, -560, 50, 50); spawn.bodyRect(750, -725, 125, 125); spawn.mapRect(1150, -1050, 250, 575); spawn.mapRect(1725, -550, 50, 200); //walls around portal 3 spawn.mapRect(1925, -550, 500, 200); spawn.mapRect(1750, -390, 200, 40); spawn.mapRect(-400, -550, 1800, 200); spawn.mapRect(-200, -1700, 150, 25); //platform above exit room spawn.mapRect(-200, -1325, 350, 25); //portal 3 angled spawn.mapRect(2425, -450, 100, 100); //portal 1 bottom spawn.mapRect(2290, -12, 375, 100); spawn.mapRect(2350, -24, 375, 100); spawn.mapRect(2410, -36, 375, 100); //portal 1 top spawn.mapRect(2290, -3012, 375, 50); spawn.mapRect(2350, -3024, 375, 50); spawn.mapRect(2410, -3036, 375, 50); spawn.mapRect(1400, -3000, 1300, 50); //floor spawn.mapRect(1750, -3050, 250, 75); spawn.mapRect(1400, -3625, 50, 200); spawn.mapRect(350, -3625, 50, 225); spawn.mapRect(350, -3260, 50, 60); spawn.mapRect(200, -3250, 1240, 50); spawn.mapRect(1400, -3260, 50, 310); spawn.bodyRect(1412, -3425, 25, 165); spawn.mapRect(-150, -2925, 150, 25); //portal 2 spawn.mapRect(-300, -2600, 300, 675); //left platform spawn.mapRect(1400, -2600, 375, 675); //right platform spawn.mapRect(1925, -2600, 775, 675); //far right platform spawn.bodyRect(2130, -2660, 50, 50); //button's block spawn.mapRect(150, -2100, 200, 175); spawn.mapRect(1050, -2100, 200, 175); //mobs spawn.randomMob(1075, -3500, -0.3); spawn.randomMob(2175, -700, -0.2); spawn.randomMob(-75, -850, -0.1); spawn.randomMob(550, -3400, 0); spawn.randomMob(0, -1175, 0.5); spawn.randomMob(-75, -1150, 0.5); spawn.randomMob(1075, -625, 0.5); spawn.randomMob(800, -3400, -0.3); spawn.randomMob(1225, -3375, -0.2); spawn.randomMob(1200, -1125, -0.1); spawn.randomMob(2050, -950, 0.5); if (simulation.difficulty > 40) { spawn.randomMob(2300, -2775, -0.5); spawn.randomMob(600, -925, -0.5); spawn.randomMob(1550, -2750, -0.5); spawn.randomMob(1350, -1150, -0.5); spawn.randomMob(-75, -1475, 0); spawn.randomGroup(600, -2600, 0); } if (simulation.difficulty > 1) { if (Math.random() < 0.5) { spawn.randomLevelBoss(700, -1550); } else { spawn.randomLevelBoss(675, -2775); //["shooterBoss", "launcherBoss", "laserTargetingBoss", "streamBoss", "shieldingBoss", "pulsarBoss", "grenadierBoss"] } } powerUps.addResearchToLevel() //needs to run after mobs are spawned spawn.secondaryBossChance(1925, -1250) if (simulation.isHorizontalFlipped) { //flip the map horizontally level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit // level.setPosToSpawn(0, -50); //-x // no need since 0 button.min.x = -button.min.x - 126 // flip the button horizontally button.max.x = -button.max.x + 126 // flip the button horizontally buttonDoor.min.x = -buttonDoor.min.x - 126 // flip the button horizontally buttonDoor.max.x = -buttonDoor.max.x + 126 // flip the button horizontally //this makes the hazard draw, but not collide for reasons I don't understand //so don't use it, instead just call the hazard differently based on this flip flag // hazard.min.x = -hazard.min.x - hazard.width //-x-width // hazard.max.x = -hazard.max.x - hazard.width //-x-width // hazard2.min.x = -hazard2.min.x - hazard2.width //-x-width // hazard2.max.x = -hazard2.max.x - hazard2.width //-x-width portal = level.portal({ x: -2475, y: -140 }, 2 * Math.PI, { //right x: -2475, y: -3140 }, 2 * Math.PI) //right portal2 = level.portal({ x: -75, y: -2150 }, -Math.PI / 2, { //up x: -1325, y: -2150 }, -Math.PI / 2) //up portal3 = level.portal({ x: -1850, y: -585 }, -Math.PI / 2, { //up x: -2425, y: -600 }, -1 * Math.PI / 3) //up left // level.custom = () => { }; // level.customTopLayer = () => {}; } else { portal = level.portal({ x: 2475, y: -140 }, Math.PI, { //left x: 2475, y: -3140 }, Math.PI) //left portal2 = level.portal({ x: 75, y: -2150 }, -Math.PI / 2, { //up x: 1325, y: -2150 }, -Math.PI / 2) //up portal3 = level.portal({ x: 1850, y: -585 }, -Math.PI / 2, { //up x: 2425, y: -600 }, -2 * Math.PI / 3) //up left } }, sewers() { const button1 = level.button(6600, 2675) // const hazard = level.hazard(4550, 2750, 4550, 150) const hazard = level.hazard(simulation.isHorizontalFlipped ? -4550 - 4550 : 4550, 2750, 4550, 150) let balance1, balance2, balance3, balance4, rotor const drip1 = level.drip(6100, 1900, 2900, 100) // drip(x, yMin, yMax, period = 100, color = "hsla(160, 100%, 35%, 0.5)") { const drip2 = level.drip(7300, 1900, 2900, 150) const drip3 = level.drip(8750, 1900, 2900, 70) level.custom = () => { drip1.draw(); drip2.draw(); drip3.draw(); button1.query(); button1.draw(); rotor.rotate(); ctx.fillStyle = "hsl(175, 15%, 76%)" ctx.fillRect(9300, 2200, 600, 400) level.exit.drawAndCheck(); level.enter.draw(); }; level.customTopLayer = () => { ctx.fillStyle = "#233" ctx.beginPath(); ctx.arc(balance1.pointA.x, balance1.pointA.y, 9, 0, 2 * Math.PI); ctx.moveTo(balance2.pointA.x, balance2.pointA.y) ctx.arc(balance2.pointA.x, balance2.pointA.y, 9, 0, 2 * Math.PI); ctx.moveTo(balance3.pointA.x, balance3.pointA.y) ctx.arc(balance3.pointA.x, balance3.pointA.y, 9, 0, 2 * Math.PI); ctx.moveTo(balance4.pointA.x, balance4.pointA.y) ctx.arc(balance4.pointA.x, balance4.pointA.y, 9, 0, 2 * Math.PI); ctx.moveTo(balance5.pointA.x, balance5.pointA.y) ctx.arc(balance5.pointA.x, balance5.pointA.y, 9, 0, 2 * Math.PI); ctx.fill(); hazard.query(); hazard.level(button1.isUp) }; level.setPosToSpawn(0, -50); //normal spawn spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); level.exit.x = 9700; level.exit.y = 2560; level.defaultZoom = 1800 simulation.zoomTransition(level.defaultZoom) document.body.style.backgroundColor = "hsl(138, 3%, 74%)"; powerUps.spawnStartingPowerUps(3475, 1775); spawn.debris(4575, 2550, 1600, 9); //16 debris per level spawn.debris(7000, 2550, 2000, 7); //16 debris per level spawn.mapRect(-500, -600, 200, 800); //left entrance wall spawn.mapRect(-400, -600, 3550, 200); //ceiling spawn.mapRect(-400, 0, 3000, 200); //floor // spawn.mapRect(300, -500, 50, 400); //right entrance wall // spawn.bodyRect(312, -100, 25, 100); spawn.bodyRect(1450, -300, 150, 50); const xPos = shuffle([600, 1250, 2000]); spawn.mapRect(xPos[0], -200, 400, 100); spawn.mapRect(xPos[1], -250, 300, 300); spawn.mapRect(xPos[2], -150, 300, 200); spawn.bodyRect(3100, 410, 75, 100); spawn.bodyRect(2450, -25, 250, 25); spawn.mapRect(3050, -600, 200, 800); //right down tube wall spawn.mapRect(3100, 0, 1200, 200); //tube right exit ceiling spawn.mapRect(4200, 0, 200, 1900); spawn.mapVertex(3500, 1000, "-500 -500 -400 -600 400 -600 500 -500 500 500 400 600 -400 600 -500 500"); spawn.mapVertex(3600, 1940, "-400 -40 -350 -90 350 -90 400 -40 400 40 350 90 -350 90 -400 40"); spawn.mapRect(3925, 2288, 310, 50); spawn.mapRect(3980, 2276, 200, 50); spawn.mapRect(2625, 2288, 650, 50); spawn.mapRect(2700, 2276, 500, 50); spawn.mapRect(2400, 0, 200, 1925); //left down tube wall spawn.mapRect(600, 2300, 3750, 200); spawn.bodyRect(3800, 275, 125, 125); spawn.mapRect(4200, 1700, 5000, 200); spawn.mapRect(4150, 2300, 200, 400); spawn.mapRect(600, 1700, 2000, 200); //bottom left room ceiling spawn.mapRect(500, 1700, 200, 800); //left wall spawn.mapRect(675, 1875, 325, 150, 0.5); spawn.mapRect(4450, 2900, 4900, 200); //boss room floor spawn.mapRect(4150, 2600, 400, 500); spawn.mapRect(6250, 2675, 700, 325); spawn.mapRect(8000, 2600, 600, 400); spawn.bodyRect(5875, 2725, 200, 200); spawn.bodyRect(6800, 2490, 50, 50); spawn.bodyRect(6800, 2540, 50, 50); spawn.bodyRect(6800, 2590, 50, 50); spawn.bodyRect(8225, 2225, 100, 100); spawn.mapRect(6250, 1875, 700, 150); spawn.mapRect(8000, 1875, 600, 150); spawn.mapRect(9100, 1700, 900, 500); //exit spawn.mapRect(9100, 2600, 900, 500); spawn.mapRect(9900, 1700, 200, 1400); //back wall // spawn.mapRect(9300, 2150, 50, 250); spawn.mapRect(9300, 2590, 650, 25); spawn.mapRect(9700, 2580, 100, 50); spawn.randomGroup(1300, 2100, 0.1); spawn.randomMob(8300, 2100, 0.1); spawn.randomSmallMob(2575, -75, 0.1); //entrance spawn.randomMob(8125, 2450, 0.1); spawn.randomSmallMob(3200, 250, 0.1); spawn.randomMob(2425, 2150, 0.1); spawn.randomSmallMob(3500, 250, 0.2); spawn.randomMob(3800, 2175, 0.2); spawn.randomSmallMob(2500, -275, 0.2); //entrance spawn.randomMob(4450, 2500, 0.2); spawn.randomMob(6350, 2525, 0.2); spawn.randomGroup(9200, 2400, 0.3); spawn.randomSmallMob(1900, -250, 0.3); //entrance spawn.randomMob(1500, 2100, 0.4); spawn.randomSmallMob(1700, -150, 0.4); //entrance spawn.randomMob(8800, 2725, 0.5); spawn.randomMob(7300, 2200, 0.5); spawn.randomMob(2075, 2025, 0.5); spawn.randomMob(3475, 2175, 0.5); spawn.randomMob(8900, 2825, 0.5); spawn.randomMob(9600, 2425, 0.9); spawn.randomMob(3600, 1725, 0.9); spawn.randomMob(4100, 1225, 0.9); spawn.randomMob(2825, 400, 0.9); if (simulation.difficulty > 1) spawn.randomLevelBoss(6000, 2300, ["spiderBoss", "launcherBoss", "laserTargetingBoss", "streamBoss", "historyBoss", "orbitalBoss", "grenadierBoss"]); powerUps.addResearchToLevel() //needs to run after mobs are spawned spawn.secondaryBossChance(7725, 2275) if (simulation.isHorizontalFlipped) { //flip the map horizontally level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit rotor = level.rotor(-5100, 2475, 0.001) //rotates other direction because flipped balance1 = level.spinner(-300 - 25, -395, 25, 390, 0.001) //entrance balance2 = level.spinner(-2605 - 390, 500, 390, 25, 0.001) //falling balance3 = level.spinner(-2608 - 584, 1900, 584, 25, 0.001) //falling balance4 = level.spinner(-9300 - 25, 2205, 25, 380, 0.001) //exit balance5 = level.spinner(-2605 - 390, 1100, 390, 25, 0.001) //falling // boost1.boostBounds.min.x = -boost1.boostBounds.min.x - 100 // boost1.boostBounds.max.x = -boost1.boostBounds.max.x + 100 // level.setPosToSpawn(300, -700); //-x // no need since 0 button1.min.x = -button1.min.x - 126 // flip the button horizontally button1.max.x = -button1.max.x + 126 // flip the button horizontally drip1.x *= -1 drip2.x *= -1 drip3.x *= -1 level.custom = () => { drip1.draw(); drip2.draw(); drip3.draw(); button1.query(); button1.draw(); rotor.rotate(); ctx.fillStyle = "hsl(175, 15%, 76%)" ctx.fillRect(-9300 - 600, 2200, 600, 400) level.exit.drawAndCheck(); level.enter.draw(); }; // level.customTopLayer = () => {}; } else { rotor = level.rotor(5100, 2475, -0.001) balance1 = level.spinner(300, -395, 25, 390, 0.001) //entrance balance2 = level.spinner(2605, 500, 390, 25, 0.001) //falling balance3 = level.spinner(2608, 1900, 584, 25, 0.001) //falling balance4 = level.spinner(9300, 2205, 25, 380, 0.001) //exit balance5 = level.spinner(2605, 1100, 390, 25, 0.001) //falling } }, satellite() { const boost1 = level.boost(5825, 235, 1400) const elevator = level.elevator(4210, -1265, 380, 50, -3450) //, 0.003, { up: 0.01, down: 0.2 } level.custom = () => { boost1.query(); ctx.fillStyle = "#d4f4f4" ctx.fillRect(-250, -750, 420, 450) ctx.fillStyle = "#d0d4d6" ctx.fillRect(-300, -1900, 500, 1100) ctx.fillRect(900, -2450, 450, 2050) ctx.fillRect(2000, -2800, 450, 2500) ctx.fillRect(3125, -3100, 450, 3300) level.exit.drawAndCheck(); level.enter.draw(); }; level.customTopLayer = () => { ctx.fillStyle = "rgba(0,20,40,0.25)" ctx.fillRect(-250, -400, 1800, 775) ctx.fillRect(1800, -275, 850, 775) ctx.fillRect(5200, 125, 450, 200) ctx.fillStyle = "rgba(0,20,40,0.1)" ctx.fillRect(4000, -1200, 1050, 1500) ctx.fillRect(4100, -3450, 600, 2250) elevator.move() }; level.setPosToSpawn(-100, 210); //normal spawn spawn.mapRect(-150, 240, 100, 30); level.exit.x = -100; level.exit.y = -425; spawn.mapRect(level.exit.x, level.exit.y + 15, 100, 50); //exit bump level.defaultZoom = 1700 // 4500 // 1400 simulation.zoomTransition(level.defaultZoom) powerUps.spawnStartingPowerUps(4900, -500); //1 per level spawn.debris(1000, 20, 1800, 3); //16 debris per level //but less here because a few mobs die from laser spawn.debris(4830, -1330, 850, 3); //16 debris per level spawn.debris(3035, -3900, 1500, 3); //16 debris per level document.body.style.backgroundColor = "#dbdcde"; //spawn start building spawn.mapRect(-350, -800, 100, 1100); // spawn.mapRect(-300, -10, 500, 50); spawn.mapRect(150, -510, 50, 365); spawn.bodyRect(170, -140, 20, 163, 1, spawn.propsFriction); //door to starting room spawn.mapVertex(175, 200, "625 0 300 0 425 -300 500 -300"); //entrance ramp // spawn.mapRect(-300, 0, 1000, 300); //ground spawn.mapRect(-350, 250, 6350, 300); //deeper ground spawn.bodyRect(2100, 50, 80, 80); spawn.bodyRect(2000, 50, 60, 60); // spawn.bodyRect(1650, 50, 300, 200); // spawn.mapRect(1800, Math.floor(Math.random() * 200), 850, 300); //stops above body from moving to right spawn.mapVertex(2225, 250, "575 0 -575 0 -450 -100 450 -100"); //base //exit building // spawn.mapRect(-100, -410, 100, 30); spawn.mapRect(-350, -850, 550, 100); spawn.mapRect(150, -800, 50, 110); spawn.bodyRect(170, -690, 14, 180, 1, spawn.propsFriction); //door to exit room spawn.mapRect(-300, -400, 500, 150); //far left starting ceiling //tall platform above exit spawn.mapRect(-500, -1900, 400, 50); //super high shade spawn.mapRect(0, -1900, 400, 50); //super high shade spawn.mapRect(-150, -1350, 200, 25); //super high shade spawn.bodyRect(140, -2100, 150, 200); //shield from laser //tall platform spawn.mapVertex(1125, -450, "325 0 250 80 -250 80 -325 0 -250 -80 250 -80"); //base spawn.mapRect(150, -500, 1410, 100); //far left starting ceiling spawn.mapRect(625, -2450, 1000, 50); //super high shade spawn.bodyRect(1300, -3600, 150, 150); //shield from laser //tall platform spawn.mapVertex(2225, -250, "325 0 250 80 -250 80 -325 0 -250 -80 250 -80"); //base spawn.mapRect(1725, -2800, 1000, 50); //super high shade spawn.mapRect(1790, -300, 870, 100); //far left starting ceiling spawn.bodyRect(2400, -2950, 150, 150); //shield from laser //tall platform spawn.mapVertex(3350, 175, "425 0 -425 0 -275 -300 275 -300"); //base spawn.bodyRect(3350, -150, 200, 120); spawn.mapRect(2850, -3150, 1000, 50); //super high shade spawn.bodyRect(3675, -3470, 525, 20); //plank spawn.bodyRect(3600, -3450, 200, 300); //plank support block //far right structure spawn.mapRect(5200, -725, 100, 870); spawn.mapRect(5300, -1075, 350, 1220); //structure bellow tall stairs spawn.mapRect(3900, -300, 450, 50); spawn.mapRect(4675, -375, 450, 50); // spawn.mapRect(4000, -1300, 1050, 100); spawn.mapRect(4000, -1300, 200, 100); spawn.mapRect(4600, -1300, 450, 100); //steep stairs spawn.mapRect(4100, -2250, 100, 650); spawn.mapRect(4100, -3450, 100, 850); //left top shelf spawn.mapRect(4600, -3450, 100, 1850); spawn.randomSmallMob(4400, -3500); spawn.randomSmallMob(4800, -800); spawn.randomMob(800, -2600); spawn.randomMob(700, -600, 0.3); spawn.randomMob(3100, -3600, 0.3); spawn.randomMob(3300, -1000, 0.3); spawn.randomMob(4200, -250, 0.3); spawn.randomMob(4900, -1500, 0.3); spawn.randomMob(3800, 175, 0.4); spawn.randomMob(5750, 125, 0.4); spawn.randomMob(5900, -1500, 0.4); spawn.randomMob(4700, -800, 0.4); spawn.randomMob(1400, 200, 0.3); spawn.randomMob(2850, 175, 0.4); spawn.randomMob(2000, -2800, 0.4); spawn.randomMob(2400, -400, 0.4); spawn.randomMob(4475, -3550, 0.3); spawn.randomGroup(5000, -2150, 1); spawn.randomGroup(3700, -4100, 0.3); spawn.randomGroup(2700, -1600, 0.1); spawn.randomGroup(1600, -100, 0); spawn.randomGroup(5000, -3900, -0.3); if (simulation.difficulty > 1) { if (Math.random() < 0.25) { spawn.randomLevelBoss(2800, -1400); } else if (Math.random() < 0.25) { spawn.laserBoss(2900 + 300 * Math.random(), -2950 + 150 * Math.random()); } else if (Math.random() < 0.33) { spawn.laserBoss(1800 + 250 * Math.random(), -2600 + 150 * Math.random()); } else if (Math.random() < 0.5) { spawn.laserBoss(3500 + 250 * Math.random(), -2600 + 1000 * Math.random()); } else { spawn.laserBoss(600 + 200 * Math.random(), -2150 + 250 * Math.random()); } } powerUps.addResearchToLevel() //needs to run after mobs are spawned spawn.secondaryBossChance(3950, -850) if (simulation.isHorizontalFlipped) { //flip the map horizontally level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit boost1.boostBounds.min.x = -boost1.boostBounds.min.x - 100 boost1.boostBounds.max.x = -boost1.boostBounds.max.x + 100 level.setPosToSpawn(100, 210); //-x elevator.holdX = -elevator.holdX // flip the elevator horizontally level.custom = () => { boost1.query(); ctx.fillStyle = "#d4f4f4" ctx.fillRect(250 - 420, -750, 420, 450) ctx.fillStyle = "#d0d4d6" ctx.fillRect(300 - 500, -1900, 500, 1100) ctx.fillRect(-900 - 450, -2450, 450, 2050) ctx.fillRect(-2000 - 450, -2800, 450, 2500) ctx.fillRect(-3125 - 450, -3100, 450, 3300) level.exit.drawAndCheck(); level.enter.draw(); }; level.customTopLayer = () => { elevator.move() ctx.fillStyle = "rgba(0,20,40,0.25)" ctx.fillRect(250 - 1800, -400, 1800, 775) ctx.fillRect(-1800 - 850, -275, 850, 775) ctx.fillRect(-5200 - 450, 125, 450, 200) ctx.fillStyle = "rgba(0,20,40,0.1)" ctx.fillRect(-4000 - 1050, -1200, 1050, 1500) ctx.fillRect(-4100 - 600, -3450, 600, 2250) }; } }, rooftops() { const elevator = level.elevator(1450, -990, 235, 45, -2000) const boost1 = level.boost(4950, 0, 1100) level.custom = () => { boost1.query(); elevator.move(); elevator.drawTrack(); ctx.fillStyle = "#d4f4f4" if (isBackwards) { ctx.fillRect(-650, -2300, 440, 300) } else { ctx.fillRect(3460, -700, 1090, 800) } level.exit.drawAndCheck(); level.enter.draw(); }; level.customTopLayer = () => { ctx.fillStyle = "rgba(0,0,0,0.1)" ctx.fillRect(710, -2225, 580, 225) ctx.fillRect(3510, -1550, 330, 300) ctx.fillRect(1735, -900, 1515, 1900) ctx.fillRect(1735, -1550, 1405, 550) ctx.fillRect(1860, -1950, 630, 350) ctx.fillRect(-700, -1950, 2100, 2950) ctx.fillRect(3400, 100, 2150, 900) ctx.fillRect(4550, -725, 900, 725) ctx.fillRect(3460, -1250, 1080, 550) if (isBackwards) { ctx.fillRect(3460, -700, 1090, 800) } else { ctx.fillRect(-650, -2300, 440, 300) } }; level.defaultZoom = 1700 simulation.zoomTransition(level.defaultZoom) document.body.style.backgroundColor = "#dcdcde"; let isBackwards = false if (Math.random() < 0.75) { //normal direction start in top left level.setPosToSpawn(-450, -2060); level.exit.x = 3600; level.exit.y = -300; spawn.mapRect(3600, -285, 100, 50); //ground bump wall //mobs that spawn in exit room spawn.bodyRect(4850, -750, 300, 25, 0.6); // spawn.randomSmallMob(4100, -100); spawn.randomSmallMob(4600, -100); spawn.randomMob(3765, -450, 0.3); } else { isBackwards = true //reverse direction, start in bottom right level.setPosToSpawn(3650, -325); level.exit.x = -550; level.exit.y = -2030; spawn.mapRect(-550, -2015, 100, 50); //ground bump wall } spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); spawn.debris(1650, -1800, 3800, 16); //16 debris per level powerUps.spawnStartingPowerUps(2450, -1675); //spawn.mapRect(-700, 0, 6250, 100); //ground spawn.mapRect(3400, 0, 2150, 100); //ground spawn.mapRect(-700, -2000, 2125, 50); //Top left ledge spawn.bodyRect(1300, -2125, 50, 125, 0.8); spawn.bodyRect(1307, -2225, 50, 100, 0.8); spawn.mapRect(-700, -2350, 50, 400); //far left starting left wall spawn.mapRect(-700, -2010, 500, 50); //far left starting ground spawn.mapRect(-700, -2350, 500, 50); //far left starting ceiling spawn.mapRect(-250, -2350, 50, 200); //far left starting right part of wall spawn.bodyRect(-240, -2150, 30, 36); //door to starting room spawn.bodyRect(-240, -2115, 30, 36); //door to starting room spawn.bodyRect(-240, -2080, 30, 35); //door to starting room spawn.bodyRect(-240, -2045, 30, 35); //door to starting room spawn.mapRect(1850, -2000, 650, 50); spawn.bodyRect(200, -2150, 80, 220, 0.8); spawn.mapRect(700, -2275, 600, 50); spawn.mapRect(1000, -1350, 410, 50); spawn.bodyRect(1050, -2350, 30, 30, 0.8); // spawn.bodyRect(1625, -1100, 100, 75); // spawn.bodyRect(1350, -1025, 400, 25); // ground plank spawn.mapRect(-725, -1000, 2150, 100); //lower left ledge spawn.bodyRect(350, -1100, 200, 100, 0.8); spawn.bodyRect(370, -1200, 100, 100, 0.8); spawn.bodyRect(360, -1300, 100, 100, 0.8); spawn.bodyRect(950, -1050, 300, 50, 0.8); spawn.bodyRect(-575, -1150, 125, 150, 0.8); spawn.mapRect(1710, -1000, 1565, 100); //middle ledge spawn.mapRect(3400, -1000, 75, 25); spawn.bodyRect(2600, -1950, 100, 250, 0.8); spawn.bodyRect(2700, -1125, 125, 125, 0.8); spawn.bodyRect(2710, -1250, 125, 125, 0.8); spawn.bodyRect(2705, -1350, 75, 100, 0.8); spawn.mapRect(3500, -1600, 350, 50); spawn.mapRect(1725, -1600, 1435, 50); spawn.bodyRect(3100, -1015, 375, 15); spawn.bodyRect(3500, -850, 75, 125, 0.8); spawn.mapRect(3450, -1000, 50, 580); //left building wall spawn.bodyRect(3460, -420, 30, 144); spawn.mapRect(5450, -775, 100, 875); //right building wall spawn.bodyRect(3925, -1400, 100, 150, 0.8); spawn.mapRect(3450, -1250, 1090, 50); // spawn.mapRect(3450, -1225, 50, 75); spawn.mapRect(4500, -1250, 50, 415); spawn.mapRect(3450, -725, 1500, 50); spawn.mapRect(5100, -725, 400, 50); spawn.mapRect(4500, -735, 50, 635); spawn.bodyRect(4500, -100, 50, 100); spawn.mapRect(4500, -885, 100, 50); spawn.spawnStairs(3800, 0, 3, 150, 206); //stairs top exit spawn.mapRect(3400, -275, 450, 275); //exit platform spawn.randomSmallMob(2200, -1775); spawn.randomSmallMob(4000, -825); spawn.randomSmallMob(-350, -3400); spawn.randomMob(4250, -1350, 0.8); spawn.randomMob(2550, -1350, 0.8); spawn.randomMob(1875, -1075, 0.3); spawn.randomMob(1120, -1200, 0.3); spawn.randomMob(3000, -1150, 0.2); spawn.randomMob(3200, -1150, 0.3); spawn.randomMob(3300, -1750, 0.3); spawn.randomMob(3650, -1350, 0.3); spawn.randomMob(3600, -1800, 0.1); spawn.randomMob(5200, -100, 0.3); spawn.randomMob(5275, -900, 0.2); spawn.randomMob(0, -1075, 0.3); spawn.randomGroup(600, -1575, 0); spawn.randomGroup(2225, -1325, 0.4); spawn.randomGroup(4900, -1200, 0); if (simulation.difficulty > 1) spawn.randomLevelBoss(3200, -1900); powerUps.addResearchToLevel() //needs to run after mobs are spawned spawn.secondaryBossChance(2175, -2425) if (simulation.isHorizontalFlipped) { //flip the map horizontally level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit boost1.boostBounds.min.x = -boost1.boostBounds.min.x - 100 boost1.boostBounds.max.x = -boost1.boostBounds.max.x + 100 elevator.holdX = -elevator.holdX // flip the elevator horizontally if (isBackwards) { level.setPosToSpawn(-3650, -325); //-x } else { level.setPosToSpawn(450, -2060); //-x } level.custom = () => { boost1.query(); elevator.move(); elevator.drawTrack(); ctx.fillStyle = "#d4f4f4" if (isBackwards) { ctx.fillRect(650 - 440, -2300, 440, 300) } else { ctx.fillRect(-3460 - 1090, -700, 1090, 800) } level.exit.drawAndCheck(); level.enter.draw(); }; level.customTopLayer = () => { ctx.fillStyle = "rgba(0,0,0,0.1)" ctx.fillRect(-710 - 580, -2225, 580, 225) ctx.fillRect(-3510 - 330, -1550, 330, 300) ctx.fillRect(-1735 - 1515, -900, 1515, 1900) ctx.fillRect(-1735 - 1405, -1550, 1405, 550) ctx.fillRect(-1860 - 630, -1950, 630, 350) ctx.fillRect(700 - 2100, -1950, 2100, 2950) ctx.fillRect(-3400 - 2150, 100, 2150, 900) ctx.fillRect(-4550 - 900, -725, 900, 725) ctx.fillRect(-3460 - 1080, -1250, 1080, 550) if (isBackwards) { ctx.fillRect(-3460 - 1090, -700, 1090, 800) } else { ctx.fillRect(650 - 440, -2300, 440, 300) } }; } }, aerie() { const boost1 = level.boost(-425, 100, 1400) const boost2 = level.boost(5350, 275, 2850); level.custom = () => { boost1.query(); boost2.query(); if (backwards) { ctx.fillStyle = "#d4f4f4" ctx.fillRect(-275, -1275, 425, 300) } else { ctx.fillStyle = "#d4f4f4" ctx.fillRect(3750, -3650, 550, 400) } ctx.fillStyle = "#c7c7ca" ctx.fillRect(4200, -2200, 100, 2600) // ctx.fillStyle = "#c7c7ca" ctx.fillRect(-100, -1000, 1450, 1400) level.exit.drawAndCheck(); level.enter.draw(); }; level.customTopLayer = () => { if (backwards) { ctx.fillStyle = "rgba(0,0,0,0.1)" ctx.fillRect(3750, -3650, 550, 400) } else { ctx.fillStyle = "rgba(0,0,0,0.1)" ctx.fillRect(-275, -1275, 425, 300) } ctx.fillStyle = "rgba(0,0,0,0.1)" ctx.fillRect(3700, -3150, 1100, 950) ctx.fillRect(2000, -1110, 450, 1550) ctx.fillStyle = "rgba(0,0,0,0.04)" ctx.beginPath() ctx.moveTo(-100, -900) ctx.lineTo(300, -900) ctx.lineTo(150, 100) ctx.lineTo(-100, 100) ctx.moveTo(600, -900) ctx.lineTo(1350, -900) ctx.lineTo(1350, 100) ctx.lineTo(750, 100) ctx.fill() }; // simulation.difficulty = 4; //for testing to simulate possible mobs spawns level.defaultZoom = 2100 simulation.zoomTransition(level.defaultZoom) const backwards = (Math.random() < 0.25 && simulation.difficulty > 8) ? true : false; if (backwards) { level.setPosToSpawn(4000, -3300); //normal spawn level.exit.x = -100; level.exit.y = -1025; } else { level.setPosToSpawn(-50, -1050); //normal spawn level.exit.x = 3950; level.exit.y = -3275; } spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); spawn.mapRect(level.exit.x, level.exit.y + 15, 100, 20); powerUps.spawnStartingPowerUps(1075, -550); document.body.style.backgroundColor = "#dcdcde"; // starting room spawn.mapRect(-300, -1000, 600, 100); spawn.mapRect(-300, -1300, 450, 50); spawn.mapRect(-300, -1300, 50, 350); if (!backwards) spawn.bodyRect(100, -1250, 200, 240); //remove on backwards //left building spawn.mapRect(-100, -975, 100, 975); spawn.mapRect(-500, 100, 1950, 400); spawn.mapRect(600, -1000, 750, 100); spawn.mapRect(900, -500, 550, 100); spawn.mapRect(1250, -975, 100, 375); spawn.bodyRect(1250, -600, 100, 100, 0.7); spawn.mapRect(1250, -450, 100, 450); spawn.bodyRect(1250, -1225, 100, 200, 0.7); //remove on backwards spawn.bodyRect(1200, -1025, 350, 35); //remove on backwards //middle super tower if (backwards) { spawn.bodyRect(2000, -800, 700, 35); } else { spawn.bodyRect(1750, -800, 700, 35); } spawn.mapVertex(2225, -2100, "0 0 450 0 300 -2500 150 -2500") spawn.mapRect(2000, -700, 450, 300); spawn.bodyRect(2360, -450, 100, 300, 0.6); spawn.mapRect(2000, -75, 450, 275); spawn.bodyRect(2450, 150, 150, 150, 0.4); spawn.mapRect(1550, 300, 4600, 200); //ground // spawn.mapRect(6050, -700, 450, 1200); spawn.mapRect(6050, -1060, 450, 1560); spawn.mapVertex(6275, -2100, "0 0 450 0 300 -2500 150 -2500") //right tall tower spawn.mapRect(3700, -3200, 100, 800); spawn.mapRect(4700, -2910, 100, 510); spawn.mapRect(3700, -2600, 300, 50); spawn.mapRect(4100, -2900, 900, 50); spawn.mapRect(3450, -2300, 750, 100); spawn.mapRect(4300, -2300, 750, 100); spawn.mapRect(4150, -1600, 200, 25); spawn.mapRect(4150, -700, 200, 25); //exit room on top of tower spawn.mapRect(3700, -3700, 600, 50); spawn.mapRect(3700, -3700, 50, 500); spawn.mapRect(4250, -3700, 50, 300); spawn.mapRect(3700, -3250, 1100, 100); spawn.randomGroup(350, -500, 1) spawn.randomSmallMob(-225, 25); spawn.randomSmallMob(2100, -900); spawn.randomSmallMob(4000, -250); spawn.randomSmallMob(4450, -3000); spawn.randomSmallMob(5600, 100); spawn.randomMob(4275, -2600, 0.8); spawn.randomMob(1050, -700, 0.8) spawn.randomMob(6050, -850, 0.7); spawn.randomMob(2150, -300, 0.6) spawn.randomMob(3900, -2700, 0.8); spawn.randomMob(3600, -500, 0.8); spawn.randomMob(3400, -200, 0.8); // spawn.randomMob(1650, -1300, 0.7) spawn.randomMob(425, 0, 0.7); spawn.randomMob(4100, -50, 0.7); spawn.randomMob(4100, -50, 0.5); spawn.randomMob(1700, -50, 0.3) spawn.randomMob(2350, -900, 0.3) spawn.randomMob(4700, -150, 0.2); spawn.randomGroup(4000, -350, 0.6); spawn.randomGroup(2750, -550, 0.1); spawn.randomMob(2175, -925, 0.5); spawn.randomMob(2750, 100, 0.5); spawn.randomMob(4250, -1725, 0.5); spawn.randomMob(3575, -2425, 0.5); spawn.randomMob(3975, -3900, 0.5); spawn.randomMob(1725, 125, 0.5); if (simulation.difficulty > 1) { if (Math.random() < 0.33) { spawn.randomLevelBoss(4250, -250); 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 } else { powerUps.chooseRandomPowerUp(4000, 200); powerUps.chooseRandomPowerUp(4000, 200); //floor below right tall tower spawn.bodyRect(3000, 50, 150, 250, 0.9); spawn.bodyRect(4500, -500, 300, 250, 0.7); spawn.bodyRect(3500, -100, 100, 150, 0.7); spawn.bodyRect(4200, -500, 110, 30, 0.7); spawn.bodyRect(3800, -500, 150, 130, 0.7); spawn.bodyRect(4000, 50, 200, 150, 0.9); spawn.bodyRect(4500, 50, 300, 200, 0.9); spawn.bodyRect(4200, -350, 200, 50, 0.9); spawn.bodyRect(4700, -350, 50, 200, 0.9); spawn.bodyRect(4900, -100, 300, 300, 0.7); spawn.suckerBoss(4500, -400); } } powerUps.addResearchToLevel() //needs to run after mobs are spawned spawn.secondaryBossChance(5350, -325) if (simulation.isHorizontalFlipped) { //flip the map horizontally level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit boost1.boostBounds.min.x = -boost1.boostBounds.min.x - 100 boost1.boostBounds.max.x = -boost1.boostBounds.max.x + 100 boost2.boostBounds.min.x = -boost2.boostBounds.min.x - 100 boost2.boostBounds.max.x = -boost2.boostBounds.max.x + 100 if (backwards) { level.setPosToSpawn(-4000, -3300); //-x } else { level.setPosToSpawn(50, -1050); //-x } level.custom = () => { boost1.query(); boost2.query(); if (backwards) { ctx.fillStyle = "#d4f4f4" ctx.fillRect(275 - 425, -1275, 425, 300) } else { ctx.fillStyle = "#d4f4f4" ctx.fillRect(-3750 - 550, -3650, 550, 400) } ctx.fillStyle = "#c7c7ca" ctx.fillRect(-4200 - 100, -2200, 100, 2600) // ctx.fillStyle = "#c7c7ca" ctx.fillRect(100 - 1450, -1000, 1450, 1400) level.exit.drawAndCheck(); level.enter.draw(); }; level.customTopLayer = () => { if (backwards) { ctx.fillStyle = "rgba(0,0,0,0.1)" ctx.fillRect(-3750 - 550, -3650, 550, 400) } else { ctx.fillStyle = "rgba(0,0,0,0.1)" ctx.fillRect(275 - 425, -1275, 425, 300) } ctx.fillStyle = "rgba(0,0,0,0.1)" ctx.fillRect(-3700 - 1100, -3150, 1100, 950) ctx.fillRect(-2000 - 450, -1110, 450, 1550) ctx.fillStyle = "rgba(0,0,0,0.04)" ctx.beginPath() ctx.moveTo(100, -900) ctx.lineTo(-300, -900) ctx.lineTo(-150, 100) ctx.lineTo(100, 100) ctx.moveTo(-600, -900) ctx.lineTo(-1350, -900) ctx.lineTo(-1350, 100) ctx.lineTo(-750, 100) ctx.fill() }; } }, skyscrapers() { const boost1 = level.boost(475, 0, 1300) const boost2 = level.boost(4450, 0, 1300); level.custom = () => { boost1.query(); boost2.query(); ctx.fillStyle = "#d4f4f4" ctx.fillRect(1350, -2100, 400, 250) ctx.fillStyle = "#d4d4d7" ctx.fillRect(3350, -1300, 50, 1325) ctx.fillRect(1300, -1800, 750, 1800) level.exit.drawAndCheck(); level.enter.draw(); }; level.customTopLayer = () => { ctx.fillStyle = "rgba(0,0,0,0.1)" ctx.fillRect(2500, -1100, 450, 250) ctx.fillRect(2400, -550, 600, 150) ctx.fillRect(2550, -1650, 250, 200) ctx.fillStyle = "rgba(0,0,0,0.2)" ctx.fillRect(700, -110, 400, 110) ctx.fillRect(3800, -110, 400, 110) ctx.fillStyle = "rgba(0,0,0,0.15)" ctx.fillRect(-250, -300, 450, 300) }; 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 simulation.zoomTransition(level.defaultZoom) powerUps.spawnStartingPowerUps(1475, -1175); spawn.debris(750, -2200, 3700, 16); //16 debris per level document.body.style.backgroundColor = "#dcdcde"; // simulation.draw.mapFill = "#444" // simulation.draw.bodyFill = "rgba(140,140,140,0.85)" // simulation.draw.bodyStroke = "#222" spawn.mapRect(-300, 0, 5100, 300); //***********ground spawn.mapRect(-300, -350, 50, 400); //far left starting left wall spawn.mapRect(-300, -10, 500, 50); //far left starting ground spawn.mapRect(-300, -350, 500, 50); //far left starting ceiling spawn.mapRect(150, -350, 50, 200); //far left starting right part of wall spawn.bodyRect(170, -130, 14, 140, 1, spawn.propsFriction); //door to starting room spawn.mapRect(700, -1100, 400, 990); //far left building spawn.mapRect(1600, -400, 1500, 500); //long center building spawn.mapRect(1345, -1100, 250, 25); //left platform spawn.mapRect(1755, -1100, 250, 25); //right platform spawn.mapRect(1300, -1850, 800, 50); //left higher platform spawn.mapRect(1300, -2150, 50, 350); //left higher platform left edge wall spawn.mapRect(1300, -2150, 450, 50); //left higher platform roof spawn.mapRect(1500, -1860, 100, 50); //ground bump wall spawn.mapRect(2400, -850, 600, 300); //center floating large square //spawn.bodyRect(2500, -1100, 25, 250); //wall before chasers spawn.mapRect(2500, -1450, 450, 350); //higher center floating large square spawn.mapRect(2500, -1675, 50, 300); //left wall on higher center floating large square spawn.mapRect(2500, -1700, 300, 50); //roof on higher center floating large square spawn.mapRect(3275, -750, 200, 25); //ledge by far right building spawn.mapRect(3275, -1300, 200, 25); //higher ledge by far right building spawn.mapRect(3800, -1100, 400, 990); //far right building spawn.bodyRect(3200, -1375, 300, 25, 0.9); spawn.bodyRect(1825, -1875, 400, 25, 0.9); // spawn.bodyRect(1800, -575, 250, 150, 0.8); spawn.bodyRect(1800, -600, 110, 150, 0.8); spawn.bodyRect(2557, -450, 35, 55, 0.7); spawn.bodyRect(2957, -450, 30, 15, 0.7); spawn.bodyRect(2900, -450, 60, 45, 0.7); spawn.bodyRect(915, -1200, 60, 100, 0.95); spawn.bodyRect(925, -1300, 50, 100, 0.95); if (Math.random() < 0.9) { spawn.bodyRect(2300, -1720, 400, 20); spawn.bodyRect(2590, -1780, 80, 80); } spawn.bodyRect(2925, -1100, 25, 250, 0.8); spawn.bodyRect(3325, -1550, 50, 200, 0.3); if (Math.random() < 0.8) { spawn.bodyRect(1400, -75, 200, 75); //block to get up ledge from ground spawn.bodyRect(1525, -125, 50, 50); //block to get up ledge from ground } spawn.bodyRect(1025, -1110, 400, 25, 0.9); //block on far left building spawn.bodyRect(1425, -1110, 115, 25, 0.9); //block on far left building spawn.bodyRect(1540, -1110, 300, 25, 0.9); //block on far left building spawn.randomMob(-100, -1300, 0.5); spawn.randomSmallMob(1850, -600); spawn.randomSmallMob(3200, -100); spawn.randomSmallMob(4450, -100); spawn.randomSmallMob(2700, -475); spawn.randomMob(2650, -975, 0.8); spawn.randomMob(2650, -1550, 0.8); spawn.randomMob(4150, -200, 0.15); spawn.randomMob(1700, -1300, 0.2); spawn.randomMob(1850, -1950, 0.25); spawn.randomMob(2610, -1880, 0.25); spawn.randomMob(3350, -950, 0.25); spawn.randomMob(1690, -2250, 0.25); spawn.randomMob(2200, -600, 0.2); spawn.randomMob(850, -1300, 0.25); spawn.randomMob(-100, -1700, -0.2); spawn.randomGroup(3700, -1500, 0.4); spawn.randomGroup(1700, -900, 0.4); if (simulation.difficulty > 1) spawn.randomLevelBoss(2600, -2300); powerUps.addResearchToLevel() //needs to run after mobs are spawned spawn.secondaryBossChance(3075, -2050) if (simulation.isHorizontalFlipped) { //flip the map horizontally level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit boost1.boostBounds.min.x = -boost1.boostBounds.min.x - 100 boost1.boostBounds.max.x = -boost1.boostBounds.max.x + 100 boost2.boostBounds.min.x = -boost2.boostBounds.min.x - 100 boost2.boostBounds.max.x = -boost2.boostBounds.max.x + 100 level.setPosToSpawn(50, -60); //-x level.custom = () => { boost1.query(); boost2.query(); ctx.fillStyle = "#d4f4f4" ctx.fillRect(-1350 - 400, -2100, 400, 250) ctx.fillStyle = "#d4d4d7" ctx.fillRect(-3350 - 50, -1300, 50, 1325) ctx.fillRect(-1300 - 750, -1800, 750, 1800) level.exit.drawAndCheck(); level.enter.draw(); }; level.customTopLayer = () => { ctx.fillStyle = "rgba(0,0,0,0.1)" ctx.fillRect(-2500 - 450, -1100, 450, 250) ctx.fillRect(-2400 - 600, -550, 600, 150) ctx.fillRect(-2550 - 250, -1650, 250, 200) ctx.fillStyle = "rgba(0,0,0,0.2)" ctx.fillRect(-700 - 400, -110, 400, 110) ctx.fillRect(-3800 - 400, -110, 400, 110) ctx.fillStyle = "rgba(0,0,0,0.15)" ctx.fillRect(250 - 450, -300, 450, 300) }; } }, highrise() { const elevator1 = level.elevator(-790, -190, 180, 25, -1150, 0.0025, { up: 0.01, down: 0.2 }, true) //x, y, width, height, maxHeight, force = 0.003, friction = { up: 0.01, down: 0.2 }) { elevator1.addConstraint(); // const button1 = level.button(-500, -200) const toggle1 = level.toggle(-300, -200) //(x,y,isOn,isLockOn = true/false) const elevator2 = level.elevator(-3630, -1000, 180, 25, -1740) //x, y, width, height, maxHeight, force = 0.003, friction = { up: 0.01, down: 0.2 }) { elevator2.addConstraint(); // const button2 = level.button(-3100, -1330) const toggle2 = level.toggle(-3100, -1330) //(x,y,isOn, isLockOn = true/false) level.custom = () => { // ctx.fillStyle = "#d0d0d2" // ctx.fillRect(-2475, -2450, 25, 750) // ctx.fillRect(-2975, -2750, 25, 600) // ctx.fillRect(-3375, -2875, 25, 725) ctx.fillStyle = "#cff" //exit ctx.fillRect(-4425, -3050, 425, 275) level.exit.drawAndCheck(); level.enter.draw(); }; level.customTopLayer = () => { // button1.draw(); toggle1.query(); if (!toggle1.isOn) { if (elevator1.isOn) { elevator1.isOn = false elevator1.frictionAir = 0.2 elevator1.addConstraint(); } } else if (!elevator1.isOn) { elevator1.isOn = true elevator1.isUp = false elevator1.removeConstraint(); elevator1.frictionAir = 0.2 //elevator.isUp ? 0.01 : 0.2 } if (elevator1.isOn) { elevator1.move(); ctx.fillStyle = "#444" } else { ctx.fillStyle = "#aaa" } ctx.fillRect(-700, -1140, 1, 975) toggle2.query(); // button2.draw(); if (!toggle2.isOn) { if (elevator2.isOn) { elevator2.isOn = false elevator2.frictionAir = 0.2 elevator2.addConstraint(); } } else if (!elevator2.isOn) { elevator2.isOn = true elevator2.isUp = false elevator2.removeConstraint(); elevator2.frictionAir = 0.2 //elevator.isUp ? 0.01 : 0.2 } if (elevator2.isOn) { elevator2.move(); ctx.fillStyle = "#444" } else { ctx.fillStyle = "#aaa" } ctx.fillRect(-3540, -1720, 1, 740) ctx.fillStyle = "rgba(64,64,64,0.97)" //hidden section ctx.fillRect(-4450, -750, 800, 200) ctx.fillStyle = "rgba(0,0,0,0.12)" ctx.fillRect(-2500, -1975, 150, 300); ctx.fillRect(-1830, -1150, 2030, 1150) ctx.fillRect(-3410, -2150, 495, 1550) ctx.fillRect(-2585, -1675, 420, 1125) ctx.fillRect(-1650, -1575, 750, 450) }; level.setPosToSpawn(-300, -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 simulation.zoomTransition(level.defaultZoom) powerUps.spawnStartingPowerUps(-2550, -700); document.body.style.backgroundColor = "#dcdcde" //"#fafcff"; 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 //3 platforms that lead to exit // spawn.mapRect(-3440, -2875, 155, 25); // spawn.mapRect(-3025, -2775, 125, 25); // spawn.mapRect(-2525, -2475, 125, 25); // spawn.bodyRect(-2600, -2500, 225, 20, 0.7); // spawn.bodyRect(-3350, -2900, 25, 25, 0.5); // spawn.bodyRect(-3400, -2950, 50, 75, 0.5); powerUps.spawn(-4300, -700, "heal"); powerUps.spawn(-4200, -700, "ammo"); powerUps.spawn(-4000, -700, "ammo"); spawn.mapRect(-4450, -1000, 100, 500); spawn.bodyRect(-3300, -750, 150, 150); //building 1 spawn.bodyRect(-1000, -675, 25, 25); spawn.mapRect(-2225, 0, 2475, 150); spawn.mapRect(175, -1000, 75, 1100); spawn.mapRect(-600, -1075, 50, 475); spawn.mapRect(-600, -650, 625, 50); spawn.mapRect(-1300, -650, 500, 50); spawn.bodyRect(-75, -300, 50, 50); spawn.mapRect(-600, -200, 500, 250); //ledge for boarding elevator spawn.bodyRect(-500, -300, 100, 100, 0.6); //a nice block near the elevator spawn.bodyRect(-425, -1375, 400, 225); spawn.mapRect(-925, -1575, 50, 475); spawn.bodyRect(-1475, -1275, 250, 125); // spawn.mapRect(-1650, -1575, 600, 50); // spawn.mapRect(-1875, -1575, 850, 50); spawn.mapRect(-1675, -1575, 650, 50); spawn.mapRect(-600, -1150, 850, 175); spawn.mapRect(-1850, -1150, 1050, 175); spawn.bodyRect(-1907, -1600, 550, 25); if (simulation.difficulty < 4) { spawn.bodyRect(-1600, -125, 125, 125); spawn.bodyRect(-1560, -200, 75, 75); } else { spawn.bodyRect(-1200, -125, 125, 125); spawn.bodyRect(-1160, -200, 75, 75); } //building 2 spawn.mapRect(-4450, -600, 2300, 750); spawn.mapRect(-2225, -450, 175, 550); // spawn.mapRect(-2600, -975, 450, 50); spawn.mapRect(-3425, -1325, 525, 75); spawn.mapRect(-3425, -2200, 525, 50); spawn.mapRect(-2600, -1700, 450, 50); // spawn.mapRect(-2600, -2450, 450, 50); spawn.bodyRect(-2275, -2700, 50, 60); // spawn.bodyRect(-2560, -1925, 250, 225); // spawn.mapRect(-2525, -2025, 125, 25); // spawn.mapRect(-2525, -1900, 125, 225); // spawn.mapRect(-2600, -1975, 250, 25); spawn.mapRect(-2515, -2000, 180, 50); spawn.bodyRect(-3410, -1425, 50, 50); spawn.bodyRect(-3390, -1525, 40, 60); // spawn.bodyRect(-3245, -1425, 100, 100); //building 3 spawn.mapRect(-4450, -1750, 800, 1050); // spawn.mapRect(-3850, -2000, 125, 400); spawn.mapRect(-4000, -2390, 200, 800); // spawn.mapRect(-4450, -2650, 475, 1000); spawn.mapRect(-4450, -2775, 475, 1125); 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); //exit spawn.mapRect(-4450, -3075, 25, 300); spawn.mapRect(-4450, -3075, 450, 25); spawn.mapRect(-4025, -3075, 25, 100); spawn.mapRect(-4275, -2785, 100, 25); spawn.bodyRect(-3900, -2400, 50, 50); //mobs spawn.randomMob(-2500, -2700, 1); spawn.randomMob(-3200, -750, 1); spawn.randomMob(-1875, -775, 0.2); spawn.randomMob(-950, -1675, 0.2); spawn.randomMob(-1525, -1750, 0.2); spawn.randomMob(-1375, -1400, 0.2); spawn.randomMob(-1625, -1275, 0.2); spawn.randomMob(-1900, -1250, 0.2); spawn.randomMob(-2250, -1850, 0.2); spawn.randomMob(-2475, -2200, 0.2); spawn.randomMob(-3000, -1475, 0.2); spawn.randomMob(-3850, -2500, 0.2); spawn.randomMob(-3650, -2125, 0.2); spawn.randomMob(-4010, -3200, 0.2); spawn.randomMob(-3500, -1825, 0.2); spawn.randomMob(-975, -100, 0); spawn.randomMob(-1050, -725, 0.2); spawn.randomMob(-1525, -100, 0); spawn.randomMob(-525, -1700, -0.1); spawn.randomMob(-125, -1500, -0.1); spawn.randomMob(-325, -1900, -0.1); spawn.randomMob(-550, -100, -0.1); spawn.randomGroup(-3250, -2700, 0.2); spawn.randomGroup(-2450, -1100, 0); if (simulation.difficulty > 1) spawn.randomLevelBoss(-2400, -2650); powerUps.addResearchToLevel() //needs to run after mobs are spawned spawn.secondaryBossChance(-1825, -1975) if (simulation.isHorizontalFlipped) { //flip the map horizontally level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit // boost1.boostBounds.min.x = -boost1.boostBounds.min.x - 100 // boost1.boostBounds.max.x = -boost1.boostBounds.max.x + 100 level.setPosToSpawn(300, -700); //-x elevator1.holdX = -elevator1.holdX // flip the elevator horizontally elevator1.removeConstraint(); elevator1.addConstraint(); elevator2.holdX = -elevator2.holdX // flip the elevator horizontally elevator2.removeConstraint(); elevator2.addConstraint(); level.custom = () => { ctx.fillStyle = "#cff" //exit ctx.fillRect(4425 - 425, -3050, 425, 275) level.exit.drawAndCheck(); level.enter.draw(); }; level.customTopLayer = () => { toggle1.query(); if (!toggle1.isOn) { if (elevator1.isOn) { elevator1.isOn = false elevator1.frictionAir = 0.2 elevator1.addConstraint(); } } else if (!elevator1.isOn) { elevator1.isOn = true elevator1.isUp = false elevator1.removeConstraint(); elevator1.frictionAir = 0.2 //elevator.isUp ? 0.01 : 0.2 } if (elevator1.isOn) { elevator1.move(); ctx.fillStyle = "#444" ctx.fillRect(700 - 1, -1140, 1, 975) } else { ctx.fillStyle = "#aaa" ctx.fillRect(700 - 1, -1140, 1, 975) } toggle2.query(); if (!toggle2.isOn) { if (elevator2.isOn) { elevator2.isOn = false elevator2.frictionAir = 0.2 elevator2.addConstraint(); } } else if (!elevator2.isOn) { elevator2.isOn = true elevator2.isUp = false elevator2.removeConstraint(); elevator2.frictionAir = 0.2 //elevator.isUp ? 0.01 : 0.2 } if (elevator2.isOn) { elevator2.move(); ctx.fillStyle = "#444" ctx.fillRect(3540 - 1, -1720, 1, 740) } else { ctx.fillStyle = "#aaa" ctx.fillRect(3540 - 1, -1720, 1, 740) } ctx.fillStyle = "rgba(64,64,64,0.97)" //hidden section ctx.fillRect(4450 - 800, -750, 800, 200) ctx.fillStyle = "rgba(0,0,0,0.12)" ctx.fillRect(2500 - 150, -1975, 150, 300); ctx.fillRect(1830 - 2030, -1150, 2030, 1150) ctx.fillRect(3410 - 495, -2150, 495, 1550) ctx.fillRect(2585 - 420, -1675, 420, 1125) ctx.fillRect(1650 - 750, -1575, 750, 450) }; } }, warehouse() { level.custom = () => { ctx.fillStyle = "#444" //light fixtures ctx.fillRect(-920, -505, 40, 10) ctx.fillRect(-920, 95, 40, 10) ctx.fillRect(180, 95, 40, 10) ctx.fillRect(-20, 695, 40, 10) ctx.fillRect(-2320, 945, 40, 10) ctx.fillStyle = "#cff" //exit ctx.fillRect(300, -250, 350, 250) level.exit.drawAndCheck(); level.enter.draw(); }; const lightingPath = new Path2D() //pre-draw the complex lighting path to save processing lightingPath.moveTo(-1800, -500) lightingPath.lineTo(-910, -500) //3rd floor light lightingPath.lineTo(-1300, 0) lightingPath.lineTo(-500, 0) lightingPath.lineTo(-890, -500) lightingPath.lineTo(-175, -500) lightingPath.lineTo(-175, -250) lightingPath.lineTo(175, -250) lightingPath.lineTo(175, 0) lightingPath.lineTo(-910, 100) //2nd floor light left lightingPath.lineTo(-1300, 600) lightingPath.lineTo(-500, 600) lightingPath.lineTo(-890, 100) lightingPath.lineTo(190, 100) //2nd floor light right lightingPath.lineTo(-200, 600) lightingPath.lineTo(600, 600) lightingPath.lineTo(210, 100) lightingPath.lineTo(1100, 100) lightingPath.lineTo(1100, 1400) lightingPath.lineTo(600, 1400) //1st floor light right lightingPath.lineTo(10, 700) lightingPath.lineTo(-10, 700) lightingPath.lineTo(-600, 1400) lightingPath.lineTo(-1950, 1400) //1st floor light left lightingPath.lineTo(-2290, 950) lightingPath.lineTo(-2310, 950) lightingPath.lineTo(-2650, 1400) lightingPath.lineTo(-3025, 1400) lightingPath.lineTo(-3025, 150) lightingPath.lineTo(-2590, 150) lightingPath.lineTo(-2600, -150) lightingPath.lineTo(-1800, -150) lightingPath.lineTo(-1800, -500) //top left end/start of path level.customTopLayer = () => { ctx.fillStyle = "rgba(0,0,0,0.15)"; //shadows and lights ctx.fill(lightingPath); }; level.setPosToSpawn(25, -55); //normal spawn level.exit.x = 425; level.exit.y = -30; level.defaultZoom = 1300 simulation.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"; spawn.mapRect(-1500, 0, 2750, 100); spawn.mapRect(175, -270, 125, 300); spawn.mapRect(-1900, -600, 1775, 100); spawn.mapRect(-1900, -550, 100, 1250); //house spawn.mapRect(-175, -550, 50, 400); spawn.mapRect(-175, -10, 350, 50); spawn.mapRect(-25, -20, 100, 50); //exit house spawn.mapRect(300, -10, 350, 50); spawn.mapRect(-150, -300, 800, 50); spawn.mapRect(600, -275, 50, 75); spawn.mapRect(425, -20, 100, 25); // spawn.mapRect(-1900, 600, 2700, 100); spawn.mapRect(1100, 0, 150, 1500); spawn.mapRect(-3150, 1400, 4400, 100); spawn.mapRect(-2375, 875, 1775, 75); spawn.mapRect(-1450, 865, 75, 435); spawn.mapRect(-1450, 662, 75, 100); spawn.bodyRect(-1418, 773, 11, 102, 1, spawn.propsFriction); //blocking path spawn.mapRect(-3150, 50, 125, 1450); spawn.mapRect(-2350, 600, 3150, 100); spawn.mapRect(-2125, 400, 250, 275); // spawn.mapRect(-1950, -400, 100, 25); spawn.mapRect(-3150, 50, 775, 100); spawn.mapRect(-2600, -250, 775, 100); let isElevators = false let elevator1, elevator2, elevator3 if (Math.random() < 0.5) { isElevators = true elevator1 = level.elevator(-1780, 500, 260, 40, 7, 0.0003) // x, y, width, height, maxHeight, force = 0.003, friction = { up: 0.01, down: 0.2 }) { elevator2 = level.elevator(820, 1300, 260, 40, 607, 0.0003) elevator3 = level.elevator(-2850, 1250, 160, 40, 600, 0.007) if (simulation.isHorizontalFlipped) { spawn.mapVertex(-2900, 225, "0 0 0 -500 -500 -500") } else { spawn.mapVertex(-2900, 225, "0 0 0 -500 500 -500") } spawn.mapRect(-3050, 1175, 175, 300); spawn.bodyRect(-2375, 1300, 100, 100); spawn.bodyRect(-2325, 1250, 50, 50); spawn.bodyRect(-2275, 1350, 125, 50); level.custom = () => { elevator1.move(); elevator1.drawTrack(); elevator2.move(); elevator2.drawTrack(); elevator3.move(); elevator3.drawTrack(); ctx.fillStyle = "#444" //light fixtures ctx.fillRect(-920, -505, 40, 10) ctx.fillRect(-920, 95, 40, 10) ctx.fillRect(180, 95, 40, 10) ctx.fillRect(-20, 695, 40, 10) ctx.fillRect(-2320, 945, 40, 10) ctx.fillStyle = "#cff" //exit ctx.fillRect(300, -250, 350, 250) level.exit.drawAndCheck(); level.enter.draw(); }; } else { spawn.mapRect(-2950, 1250, 175, 250); spawn.mapRect(-3050, 1100, 150, 400); spawn.bodyRect(-1450, -125, 125, 125, 1, spawn.propsSlide); //weight spawn.bodyRect(-1800, 0, 300, 100, 1, spawn.propsHoist); //hoist cons[cons.length] = Constraint.create({ pointA: { x: -1650, y: -500 }, bodyB: body[body.length - 1], stiffness: 0.0001815, length: 1 }); Composite.add(engine.world, cons[cons.length - 1]); spawn.bodyRect(600, 525, 125, 125, 1, spawn.propsSlide); //weight spawn.bodyRect(800, 600, 300, 100, 1, spawn.propsHoist); //hoist cons[cons.length] = Constraint.create({ pointA: { x: 950, y: 100 }, bodyB: body[body.length - 1], stiffness: 0.0001815, length: 1 }); Composite.add(engine.world, cons[cons.length - 1]); spawn.bodyRect(-2700, 1150, 100, 160, 1, spawn.propsSlide); //weight spawn.bodyRect(-2550, 1200, 150, 150, 1, spawn.propsSlide); //weight spawn.bodyRect(-2763, 1300, 350, 100, 1, spawn.propsHoist); //hoist cons[cons.length] = Constraint.create({ pointA: { x: -2575, y: 150 }, bodyB: body[body.length - 1], stiffness: 0.0004, length: 566 }); Composite.add(engine.world, cons[cons.length - 1]); } //blocks spawn.bodyRect(-165, -150, 30, 35, 1); spawn.bodyRect(-165, -115, 30, 35, 1); spawn.bodyRect(-165, -80, 30, 35, 1); spawn.bodyRect(-165, -45, 30, 35, 1); 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(-2525, -50, 145, 100, 0.5); spawn.bodyRect(-2325, -300, 150, 100, 0.5); spawn.bodyRect(-1275, -750, 200, 150, 0.5); //roof block spawn.bodyRect(-525, -700, 125, 100, 0.5); //roof block //mobs spawn.randomSmallMob(-1125, 550); spawn.randomSmallMob(-2950, -50); spawn.randomMob(-2025, 175, 0.3); spawn.randomMob(-2325, 450, 0.3); spawn.randomMob(-2925, 675, 0.2); spawn.randomMob(-2700, 300, 0.1); spawn.randomMob(-2500, 300, 0.1); spawn.randomMob(-2075, -425, 0.1); spawn.randomMob(-1550, -725, 0.1); spawn.randomMob(375, 1100, 0); spawn.randomMob(-1575, 1100, 0); spawn.randomSmallMob(825, 300); spawn.randomMob(-800, -1750, 0); spawn.randomMob(400, -750, -0.1); spawn.randomMob(650, 1300, -0.1); spawn.randomMob(-2450, 1050, -0.1); spawn.randomMob(500, 400, -0.1); spawn.randomMob(-75, -1700, -0.1); spawn.randomMob(900, -800, -0.2); spawn.randomGroup(-75, 1050, -0.1); spawn.randomGroup(-900, 1000, 0.2); spawn.randomGroup(-1300, -1100, -0.3); spawn.randomSmallMob(-2325, 800); spawn.randomSmallMob(-900, 825); if (simulation.difficulty > 1) { if (Math.random() < 0.70) { spawn.randomLevelBoss(-800, -1300) } else { spawn.snakeBoss(-1000 + Math.random() * 2500, -1300); //boss snake with head } } powerUps.addResearchToLevel() //needs to run after mobs are spawned spawn.secondaryBossChance(300, -800) if (simulation.isHorizontalFlipped) { //flip the map horizontally level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit // boost1.boostBounds.min.x = -boost1.boostBounds.min.x - 100 // boost1.boostBounds.max.x = -boost1.boostBounds.max.x + 100 level.setPosToSpawn(-25, -55); //-x if (isElevators) { elevator1.holdX = -elevator1.holdX // flip the elevator horizontally elevator2.holdX = -elevator2.holdX // flip the elevator horizontally elevator3.holdX = -elevator3.holdX // flip the elevator horizontally level.custom = () => { elevator1.move(); elevator1.drawTrack(); elevator2.move(); elevator2.drawTrack(); elevator3.move(); elevator3.drawTrack(); ctx.fillStyle = "#444" //light fixtures ctx.fillRect(920 - 40, -505, 40, 10) ctx.fillRect(920 - 40, 95, 40, 10) ctx.fillRect(-180 - 40, 95, 40, 10) ctx.fillRect(20 - 40, 695, 40, 10) ctx.fillRect(2320 - 40, 945, 40, 10) ctx.fillStyle = "#cff" //exit ctx.fillRect(-300 - 350, -250, 350, 250) level.exit.drawAndCheck(); level.enter.draw(); }; } else { level.custom = () => { ctx.fillStyle = "#444" //light fixtures ctx.fillRect(920 - 40, -505, 40, 10) ctx.fillRect(920 - 40, 95, 40, 10) ctx.fillRect(-180 - 40, 95, 40, 10) ctx.fillRect(20 - 40, 695, 40, 10) ctx.fillRect(2320 - 40, 945, 40, 10) ctx.fillStyle = "#cff" //exit ctx.fillRect(-300 - 350, -250, 350, 250) level.exit.drawAndCheck(); level.enter.draw(); }; } level.customTopLayer = () => { ctx.fillStyle = "rgba(0,0,0,0.15)"; //shadows and lights ctx.beginPath() ctx.moveTo(1800, -500) ctx.lineTo(910, -500) //3rd floor light ctx.lineTo(1300, 0) ctx.lineTo(500, 0) ctx.lineTo(890, -500) ctx.lineTo(175, -500) ctx.lineTo(175, -250) ctx.lineTo(-175, -250) ctx.lineTo(-175, 0) ctx.lineTo(910, 100) //2nd floor light left ctx.lineTo(1300, 600) ctx.lineTo(500, 600) ctx.lineTo(890, 100) ctx.lineTo(-190, 100) //2nd floor light right ctx.lineTo(200, 600) ctx.lineTo(-600, 600) ctx.lineTo(-210, 100) ctx.lineTo(-1100, 100) ctx.lineTo(-1100, 1400) ctx.lineTo(-600, 1400) //1st floor light right ctx.lineTo(-10, 700) ctx.lineTo(10, 700) ctx.lineTo(600, 1400) ctx.lineTo(1950, 1400) //1st floor light left ctx.lineTo(2290, 950) ctx.lineTo(2310, 950) ctx.lineTo(2650, 1400) ctx.lineTo(3025, 1400) ctx.lineTo(3025, 150) ctx.lineTo(2590, 150) ctx.lineTo(2600, -150) ctx.lineTo(1800, -150) ctx.lineTo(1800, -500) //top left end/start of path ctx.fill() }; } }, office() { let button, door let isReverse = false if (Math.random() < 0.75) { //normal direction start in top left button = level.button(525, 0) door = level.door(1362, -200, 25, 200, 195) level.setPosToSpawn(1375, -1550); //normal spawn level.exit.x = 3088; level.exit.y = -630; } else { //reverse direction, start in bottom right isReverse = true button = level.button(3800, 0) door = level.door(3012, -200, 25, 200, 195) level.setPosToSpawn(3137, -650); //normal spawn level.exit.x = 1375; level.exit.y = -1530; } level.custom = () => { button.query(); button.draw(); if (button.isUp) { door.isClosing = true } else { door.isClosing = false } door.openClose(); ctx.fillStyle = "#ccc" ctx.fillRect(2495, -500, 10, 525) ctx.fillStyle = "#dff" if (isReverse) { ctx.fillRect(725, -1950, 825, 450) } else { ctx.fillRect(3050, -950, 625, 500) } level.exit.drawAndCheck(); level.enter.draw(); }; level.customTopLayer = () => { ctx.fillStyle = "rgba(0,0,0,0.1)" ctx.fillRect(3650, -1300, 1300, 1300) ctx.fillRect(3000, -1000, 650, 1000) ctx.fillRect(750, -1950, 800, 450) ctx.fillRect(750, -1450, 650, 1450) ctx.fillRect(-550, -1700, 1300, 1700) // ctx.fillRect(0, 0, 0, 0) door.draw(); }; level.defaultZoom = 1400 simulation.zoomTransition(level.defaultZoom) spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 50); //ground bump wall spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); document.body.style.backgroundColor = "#e0e5e0"; spawn.debris(-300, -200, 1000, 6); //ground debris //16 debris per level spawn.debris(3500, -200, 800, 5); //ground debris //16 debris per level spawn.debris(-300, -650, 1200, 5); //1st floor debris //16 debris per level powerUps.spawnStartingPowerUps(-525, -700); spawn.mapRect(-600, 0, 2000, 325); //ground spawn.mapRect(1400, 25, 1600, 300); //ground spawn.mapRect(3000, 0, 2000, 325); //ground spawn.mapRect(-600, -1700, 50, 2000 - 100); //left wall spawn.bodyRect(-295, -1540, 40, 40); //center block under wall spawn.bodyRect(-298, -1580, 40, 40); //center block under wall spawn.bodyRect(1500, -1540, 30, 30); //left of entrance spawn.mapRect(1550, -2000, 50, 550); //right wall spawn.mapRect(1350, -2000 + 505, 50, 1295); //right wall spawn.mapRect(-600, -2000 + 250, 2000 - 700, 50); //roof left spawn.mapRect(-600 + 1300, -2000, 50, 300); //right roof wall spawn.mapRect(-600 + 1300, -2000, 900, 50); //center wall map[map.length] = Bodies.polygon(725, -1700, 0, 15); //circle above door spawn.bodyRect(720, -1675, 15, 170, 1, spawn.propsDoor); // door body[body.length - 1].isNotHoldable = true; //makes door swing consBB[consBB.length] = Constraint.create({ bodyA: body[body.length - 1], pointA: { x: 0, y: -90 }, bodyB: map[map.length - 1], stiffness: 1 }); Composite.add(engine.world, consBB[consBB.length - 1]); spawn.mapRect(-600 + 300, -2000 * 0.75, 1900, 50); //3rd floor spawn.mapRect(-600 + 2000 * 0.7, -2000 * 0.74, 50, 375); //center wall spawn.bodyRect(-600 + 2000 * 0.7, -2000 * 0.5 - 106, 50, 106); //center block under wall spawn.mapRect(-600, -1000, 1100, 50); //2nd floor spawn.mapRect(600, -1000, 500, 50); //2nd floor spawn.spawnStairs(-600, -1000, 4, 250, 350); //stairs 2nd spawn.mapRect(375, -600, 350, 150); //center table spawn.mapRect(-300, -2000 * 0.25, 1690, 50); //1st floor spawn.spawnStairs(-610 + 2000 - 50, -500, 4, 250, 350, true); //stairs spawn.spawnStairs(-600, 0, 4, 250, 350); //stairs ground spawn.bodyRect(700, -200, 100, 100); //center block under wall spawn.bodyRect(700, -300, 100, 100); //center block under wall spawn.bodyRect(700, -400, 100, 100); //center block under wall spawn.mapRect(1390, 13, 30, 20); //step left spawn.mapRect(2980, 13, 30, 20); //step right spawn.bodyRect(4250, -700, 50, 100); spawn.mapRect(3000, -1000, 50, 800); //left wall spawn.mapRect(3000 + 2000 - 50, -1300, 50, 1100); //right wall spawn.mapRect(4150, -600, 350, 150); //table spawn.mapRect(3650, -1300, 50, 700); //exit wall spawn.mapRect(3650, -1300, 1350, 50); //exit wall spawn.bodyRect(3665, -600, 20, 100); //door spawn.mapRect(3025, -600, 250, 125); spawn.mapRect(3175, -550, 175, 75); // spawn.mapVertex(3160, -525, "625 0 300 0 300 -140 500 -140"); //entrance/exit ramp spawn.mapRect(3000, -2000 * 0.5, 700, 50); //exit roof spawn.mapRect(3010, -2000 * 0.25, 1690, 50); //1st floor spawn.spawnStairs(3000 + 2000 - 50, 0, 4, 250, 350, true); //stairs ground spawn.randomSmallMob(4575, -560, 1); spawn.randomSmallMob(1315, -880, 1); spawn.randomSmallMob(800, -600); spawn.randomMob(4100, -225, 0.8); spawn.randomMob(-250, -700, 0.8); spawn.randomMob(4500, -225, 0.15); spawn.randomMob(3250, -225, 0.15); spawn.randomMob(-100, -225, 0.1); spawn.randomMob(1150, -225, 0.15); spawn.randomMob(2000, -225, 0.15); spawn.randomMob(450, -225, 0.15); spawn.randomMob(100, -1200, 1); spawn.randomMob(950, -1150, -0.1); spawn.randomGroup(1800, -800, -0.2); spawn.randomGroup(4150, -1000, 0.6); if (simulation.difficulty > 1) { if (Math.random() < 0.5) { spawn.tetherBoss(2850, -80, { x: 2500, y: -500 }) //chance to spawn a ring of exploding mobs around this boss if (simulation.difficulty > 6) spawn.nodeGroup(2850, -80, "spawns", 8, 20, 105); } else { spawn.randomLevelBoss(2200, -450) } } powerUps.addResearchToLevel() //needs to run after mobs are spawned spawn.secondaryBossChance(1875, -675) if (simulation.isHorizontalFlipped) { //flip the map horizontally level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit level.setPosToSpawn(50, -60); if (!isReverse) { //normal direction start in top left level.setPosToSpawn(-1375, -1550); //normal spawn //-x } else { //reverse direction, start in bottom right level.setPosToSpawn(-3137, -650); //normal spawn } button.min.x = -button.min.x - 126 // flip the button horizontally button.max.x = -button.max.x + 126 // flip the button horizontally level.custom = () => { button.query(); button.draw(); if (button.isUp) { door.isClosing = true } else { door.isClosing = false } door.openClose(); ctx.fillStyle = "#ccc" ctx.fillRect(-2495 - 10, -500, 10, 525) ctx.fillStyle = "#dff" if (isReverse) { ctx.fillRect(-725 - 825, -1950, 825, 450) } else { ctx.fillRect(-3050 - 625, -950, 625, 500) } level.exit.drawAndCheck(); level.enter.draw(); }; level.customTopLayer = () => { ctx.fillStyle = "rgba(0,0,0,0.1)" ctx.fillRect(-3650 - 1300, -1300, 1300, 1300) ctx.fillRect(-3000 - 650, -1000, 650, 1000) ctx.fillRect(-750 - 800, -1950, 800, 450) ctx.fillRect(-750 - 650, -1450, 650, 1450) ctx.fillRect(550 - 1300, -1700, 1300, 1700) // ctx.fillRect(0, 0, 0, 0) door.draw(); }; } }, stronghold() { // player made level by Francois 👑 from discord const boost1 = level.boost(1470, -250, 1080) const boost2 = level.boost(-370, 0, 800) const boost3 = level.boost(4865, 0, 1800) level.custom = () => { boost1.query(); boost2.query(); boost3.query(); ctx.fillStyle = "#edf9f9"; ctx.fillRect(-500, -1220, 550, -480); ctx.fillStyle = "rgba(0,0,0,0.1)"; ctx.fillRect(0, -700, 1050, 700); ctx.fillRect(-550, -1170, 550, 1170); ctx.fillRect(1150, -1700, 250, 1700); ctx.fillRect(1100, -1700, 50, 450); ctx.fillRect(1050, -1200, 100, 1200); ctx.fillRect(1400, -250, 200, -1500); ctx.fillRect(1600, -550, 600, -1150); ctx.fillRect(2530, -550, 430, -1450); ctx.fillRect(3270, -1700, 80, 600); ctx.fillRect(3350, -1350, 700, 230); ctx.fillRect(4050, -1700, 600, 1290); ctx.fillRect(3650, -110, 1000, 170); ctx.fillRect(4865, -55, 100, 55); level.exit.drawAndCheck(); level.enter.draw(); }; level.customTopLayer = () => { }; level.setPosToSpawn(1900, -40); //normal spawn level.exit.x = -350; level.exit.y = -1250; level.defaultZoom = 1400 simulation.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); document.body.style.backgroundColor = "#dbdcde"; // simulation.draw.mapFill = "#444" // simulation.draw.bodyFill = "rgba(140,140,140,0.85)" // simulation.draw.bodyStroke = "#222" // __________________________________________________________________________________________________ // Spawn Box spawn.mapRect(1600, -500, 50, 500); //Left Wall spawn.mapRect(1600, -550, 1500, 50); //Roof spawn.mapRect(2300, -500, 50, 300); //Right Wall spawn.mapRect(-550, 0, 4300, 200); //ground spawn.mapRect(3700, 55, 1300, 145); //2nd ground spawn.mapRect(5000, 0, 50, 200); //Last small part of the ground spawn.mapRect(3100, -1070, 50, 570); // vertical 2nd roof spawn.mapRect(3100, -1120, 950, 50); // Horizontal 2nd Roof spawn.mapRect(4050, -1750, 600, 50); // Roof after lift spawn.mapRect(4600, -1700, 50, 100); // Petit retour de toit, après ascenseur //Spawn "Upstairs" spawn.mapRect(3650, -160, 400, 50); //Thin Walk spawn.mapRect(4050, -410, 600, 300); //Large staircase block spawn.mapRect(4600, -1120, 50, 710); //Left Wall Wall upstairs spawn.mapRect(4550, -1170, 100, 50); //Bloque ascenseur spawn.mapVertex(3700, 35, "0 0 450 0 300 -60 150 -60"); //first slope spawn.mapVertex(4850, 35, "0 0 370 0 370 -65 150 -65"); //second slope spawn.bodyRect(3950, -280, 170, 120); //Bloc Marche Pour Monter À Ascenseur // spawn.bodyRect(-2700, 1150, 100, 160, 1, spawn.propsSlide); //weight // spawn.bodyRect(-2550, 1150, 200, 100, 1, spawn.propsSlide); //weight spawn.bodyRect(4050, -500, 275, 100, 1, spawn.propsSlide); //weight spawn.bodyRect(4235, -500, 275, 100, 1, spawn.propsSlide); //weight // spawn.bodyRect(-2775, 1300, 400, 100, 1, spawn.propsHoist); //hoist spawn.bodyRect(4025, -450, 550, 100, 1, spawn.propsHoist); //hoist cons[cons.length] = Constraint.create({ pointA: { x: 4325, y: -1700, }, bodyB: body[body.length - 1], stiffness: 0.0002, //1217, length: 200 }); Composite.add(engine.world, cons[cons.length - 1]); spawn.bodyRect(2799, -870, 310, 290); //Gros bloc angle toit spawn.mapRect(4000, -1750, 50, 400); //Right Wall Cuve spawn.mapRect(3400, -1400, 600, 50); // Bottom Cuve spawn.mapRect(3350, -1750, 50, 400); // Left Wall Cuve spawn.bodyRect(3400, -1470, 110, 70); //Moyen bloc dans la cuve spawn.mapRect(3270, -1750, 80, 50); // Rebord gauche cuve spawn.mapRect(2530, -2000, 430, 50); //First Plateforme spawn.mapRect(1600, -1750, 600, 50); // Middle plateforme spawn.mapRect(1100, -1750, 300, 50); //Derniere plateforme // Toit petite boite en [ spawn.bodyRect(1830, -1980, 190, 230); // Fat bloc plateforme middle spawn.bodyRect(1380, -1770, 250, 20) // Pont last plateforme spawn.mapRect(1000, -1250, 400, 50); //Sol de la petite boite en [ spawn.mapRect(1100, -1550, 50, 190); //Mur gauche petite boite en [ spawn.bodyRect(1100, -1380, 48, 109); //Bloc-porte petite boite en [ spawn.mapRect(-100, -750, 1100, 50); //Sol last salle spawn.mapRect(1000, -1200, 50, 500) // Mur droit last salle spawn.mapRect(50, -1550, 1050, 50); // Toit last salle spawn.bodyRect(1, -900, 48, 150); //Bloc porte last salle spawn.mapRect(0, -1170, 50, 270); //Mur gauche en bas last salle spawn.bodyRect(920, -900, 120, 120); //Gros bloc last salle spawn.mapRect(0, -1700, 50, 320); // Mur droit salle exit / Mur gauche last salle spawn.mapRect(-550, -1220, 600, 50); // Sol exit room spawn.mapRect(-500, -1750, 550, 50); // Toit exit room spawn.mapRect(-550, -1750, 50, 530); // Mur gauche exit room spawn.bodyRect(-503, -1250, 30, 30); // Petit bloc exit room spawn.mapRect(500, -700, 100, 590); //Bloc noir un dessous last salle spawn.mapRect(1350, -250, 250, 250); //Black Block left from the spawn map[map.length] = Bodies.polygon(2325, -205, 0, 15); //circle above door spawn.bodyRect(2325, -180, 15, 170, 1, spawn.propsDoor); // door body[body.length - 1].isNotHoldable = true; //makes door swing consBB[consBB.length] = Constraint.create({ bodyA: body[body.length - 1], pointA: { x: 0, y: -90 }, bodyB: map[map.length - 1], stiffness: 1 }); Composite.add(engine.world, consBB[consBB.length - 1]); spawn.bodyRect(650, 50, 70, 50); spawn.bodyRect(300, 0, 100, 60); spawn.bodyRect(400, 0, 100, 150); spawn.bodyRect(2545, -50, 70, 50); spawn.bodyRect(2550, 0, 100, 30); spawn.randomSmallMob(200, -1300, 0.5); spawn.randomSmallMob(300, -1300, 0.9); spawn.randomSmallMob(470, -650, 1); spawn.randomSmallMob(1000, -400, 1); spawn.randomSmallMob(2550, -560, 1); spawn.randomSmallMob(3350, -900, 1); spawn.randomSmallMob(3600, -1210, 1); spawn.randomSmallMob(700, -1950, 0.2); spawn.randomSmallMob(5050, -550); spawn.randomMob(-250, -250, 0.8); spawn.randomMob(-300, -600, 0.6); spawn.randomMob(350, -900, 0.5); spawn.randomMob(770, -950, 0.8) spawn.randomMob(900, -160, 1); spawn.randomMob(2360, -820, 0.8); spawn.randomMob(2700, -2020, 0.8); spawn.randomMob(3050, -1650, 0.8); spawn.randomMob(3350, -600, 0.8); spawn.randomMob(4400, -50, 1); spawn.randomGroup(1500, -1900, 0.5); spawn.randomGroup(2350, -850, 1); spawn.randomGroup(100, -450, 0.9); if (simulation.difficulty > 1) spawn.randomLevelBoss(1850, -1400); spawn.secondaryBossChance(1850, -1400) powerUps.addResearchToLevel() //needs to run after mobs are spawned }, basement() { // player made level by Francois 👑 from discord let button, door, buttonDoor, buttonPlateformEnd, doorPlateform let isLevelReversed = Math.random(); if (isLevelReversed < 0.7) { isLevelReversed = false; } else { isLevelReversed = true; } const elevator = level.elevator(4545, -220, 110, 30, -3000) const hazard = level.hazard(1675, -1050, 800, 150); const portal = level.portal({ x: -620, y: -257 }, Math.PI / 2, { //down x: 500, y: 2025 }, -Math.PI / 2) //up spawn.mapRect(350, 2025, 300, 300); //Bloc portail n°2 if (isLevelReversed === false) { /// Normal Spawn button = level.button(2700, -1150); level.setPosToSpawn(2600, -2050); //normal spawn level.exit.x = level.enter.x + 4510; level.exit.y = level.enter.y + 600; spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20); spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); } else { /// Reversed spawn button = level.button(1450, -1150); buttonPlateformEnd = level.button(3530, -1150); buttonDoor = level.button(8033, -3625); door = level.door(7700, -3905, 25, 184, 184); doorPlateform = level.door(3200, -1225, 299, 80, 525); level.setPosToSpawn(7110, -1450); //normal spawn level.exit.x = level.enter.x - 4510; level.exit.y = level.enter.y - 600; spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20); spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); spawn.mapRect(7675, -3935, 75, 25); spawn.mapRect(7675, -3715, 75, 25); spawn.bodyRect(8075, -3675, 50, 25); } const boost1 = level.boost(8290, -2100, 1800) level.custom = () => { boost1.query(); level.exit.drawAndCheck(); portal[2].query() portal[3].query() button.query(); button.draw(); if (isLevelReversed === true) { ///Reversed spawn buttonDoor.draw(); buttonDoor.query(); buttonPlateformEnd.draw(); buttonPlateformEnd.query(); // hazard.query(); //bug reported from discord? if (buttonDoor.isUp) { door.isClosing = false } else { door.isClosing = true } door.openClose(); if (buttonPlateformEnd.isUp) { doorPlateform.isClosing = true; } else { doorPlateform.isClosing = false; } door.openClose(); doorPlateform.openClose(); } hazard.level(button.isUp) level.enter.draw(); elevator.move(); elevator.drawTrack(); }; level.customTopLayer = () => { ctx.fillStyle = "rgba(61,62,62,0.95)"; ctx.fillRect(-750, -900, 750, 450); if (isLevelReversed === true) { door.draw(); doorPlateform.draw(); } portal[0].draw(); portal[1].draw(); portal[2].draw(); portal[3].draw(); hazard.query(); }; level.defaultZoom = 1300 simulation.zoomTransition(level.defaultZoom) document.body.style.backgroundColor = "#c7c7c7"; // GROUND // spawn.mapRect(-400, -2000, 400, 1430); //Gros left wall spawn.mapRect(3700, -3000, 700, 2650); //Gros right wall //Puit spawn.mapRect(-400, -2000, 3700, 250); //Ground spawn.mapRect(2475, -1150, 1225, 250); spawn.mapRect(500, -1150, 1175, 250); //Ground level 3 spawn.mapRect(350, -180, 4600, 1255); // Last ground spawn.mapRect(-400, -458, 750, 3337); //mur left sous-sol spawn.mapRect(-2850, -3375, 5300, 1375); spawn.mapRect(-2850, -4200, 8000, 825); spawn.mapRect(3700, -3375, 550, 375); spawn.mapRect(-2850, -5200, 10200, 1000); spawn.mapRect(5600, -1250, 3550, 2000); spawn.mapRect(9150, -5200, 1725, 5800); // SPAWN BOX // spawn.mapRect(2300, -3375, 950, 1000); spawn.mapRect(3550, -3375, 150, 1625); spawn.mapVertex(2020, -791, " 250 250 -860 250 -2200 0 250 0"); //map vertex en haut spawn.mapVertex(690, -295, "1700 0 -200 0 -200 -284 500 -284"); //map vertex en bas spawn.mapRect(2950, -900, 750, 250); //Extension ground apres map vertex if (isLevelReversed === false) { spawn.mapRect(3250, -1800, 50, 150); //Petit picot en haut, à gauche spawn.mapRect(3400, -1800, 50, 150); //Petit picot en haut, à droite spawn.mapRect(3150, -1300, 50, 200) //Petit picot en bas, à gauche spawn.mapRect(3500, -1300, 50, 200) //Petit picot en bas, à droite spawn.mapRect(3050, -3375, 500, 1260); spawn.mapRect(3400, -2265, 150, 515); //Mur fond tunnel spawn.bodyRect(3625, -1225, 75, 75); //Pitit bloc à droite en bas spawn } else { spawn.mapRect(3050, -3375, 500, 1000); spawn.mapRect(3400, -2400, 150, 650); //Mur fond tunnel spawn.bodyRect(3425, -1515, 75, 75); //Petit en bas spawn spawn.mapRect(3200, -1275, 300, 175); } // TRAMPOLING // if (isLevelReversed === false) { /// Normal spawn spawn.bodyRect(0, -1000, 500, 120, 1, spawn.propsHoist); //hoist cons[cons.length] = Constraint.create({ pointA: { x: 250, y: -1750, }, bodyB: body[body.length - 1], stiffness: 0.00014, length: 120 }); Composite.add(engine.world, cons[cons.length - 1]); spawn.bodyRect(0, -1250, 240, 190) //Fat cube ascenseur } else { /// Reversed spawn spawn.bodyRect(0, -650, 225, 175); spawn.mapRect(425, -950, 175, 50); spawn.mapRect(-25, -1150, 100, 50); } // PUIT // spawn.mapVertex(4200, -1810, "0 0 450 0 600 -2500 0 -2500") spawn.mapVertex(5000, -1809, "0 0 450 0 450 -2500 -150 -2500") spawn.mapRect(4800, -3000, 800, 5875); //big right Puit // BOSS AREA // spawn.mapRect(4800, -3150, 50, 200); //Premiere barriere spawn.mapRect(5100, -3530, 50, 380); //2nd barriere spawn.mapRect(5100, -3200, 150, 50); //Marche en dessous mapVertex 1 spawn.mapVertex(5450, -3650, "220 0 200 30 -200 30 -220 0 -200 -30 200 -30"); spawn.mapVertex(6225, -3350, "275 0 250 50 -250 50 -275 0 -250 -50 250 -50"); spawn.mapRect(5600, -3000, 1600, 725); //ground Boss Area //Ouverture right boss area spawn.mapRect(7300, -3325, 50, 50); //petite marche pour accéder à l'ouverture spawn.mapRect(7350, -4075, 850, 50); //Bouche spawn.mapRect(7400, -4050, 800, 50); //Bouche spawn.mapRect(7450, -4025, 750, 50); //Bouche spawn.mapRect(7500, -4000, 700, 50); //Bouche spawn.mapRect(7550, -3975, 650, 50); //Bouche spawn.mapRect(7350, -3600, 850, 50); //Bouche spawn.mapRect(7400, -3625, 800, 50); //Bouche spawn.mapRect(7450, -3650, 575, 50); //Bouche spawn.mapRect(7500, -3675, 525, 50); //Bouche spawn.mapRect(7550, -3700, 475, 50); //Bouche //Murs spawn.mapRect(7350, -5200, 1800, 1125); spawn.mapRect(8475, -4075, 675, 2825); spawn.mapRect(7300, -2100, 1175, 850); spawn.mapRect(7350, -3550, 850, 1275); //Escaliers spawn.mapRect(6600, -2100, 200, 75); //escaliers spawn.mapRect(6750, -2100, 750, 250); //escaliers spawn.mapRect(6950, -1850, 550, 200); //escaliers spawn.mapRect(6750, -1400, 750, 150); //escaliers spawn.mapRect(6550, -1625, 250, 375); //escaliers spawn.mapRect(6350, -1800, 250, 550); //escaliers spawn.mapRect(5600, -2275, 800, 1025); //escaliers // BLOCS if (isLevelReversed === false) { /// Normal spawn spawn.bodyRect(1350, -1175, 225, 25); spawn.bodyRect(1450, -1200, 25, 25); } else { /// Reversed spawn spawn.bodyRect(700, -1175, 225, 25); spawn.bodyRect(800, -1200, 25, 25); } spawn.bodyRect(1100, -1375, 225, 225); spawn.bodyRect(1775, -925, 75, 25); spawn.bodyRect(2225, -950, 75, 50); spawn.bodyRect(2000, -1000, 50, 100); spawn.bodyRect(3100, -1175, 50, 25); spawn.bodyRect(2200, -375, 50, 50); spawn.bodyRect(2200, -425, 50, 50); spawn.bodyRect(2200, -475, 50, 50); spawn.bodyRect(2200, -525, 50, 50); spawn.bodyRect(1050, -400, 50, 25); spawn.mapRect(2200, -650, 50, 125); spawn.mapRect(2200, -325, 50, 150); spawn.mapRect(2875, -225, 250, 50); spawn.mapRect(2050, -1225, 75, 100); //Plateforme over acid // MOBS if (isLevelReversed === false) { ///Normal spawn if (simulation.difficulty > 1) { if (Math.random() < 0.2) { // tether ball spawn.tetherBoss(7000, -3300, { x: 7300, y: -3300 }) if (simulation.difficulty > 4) spawn.nodeGroup(7000, -3300, "spawns", 8, 20, 105); } else { spawn.randomLevelBoss(6100, -3600, ["shooterBoss", "launcherBoss", "laserTargetingBoss", "spiderBoss", "laserBoss", "pulsarBoss"]); } } } else { /// Reversed spawn if (simulation.difficulty > 1) { if (Math.random() < 0.2) { // tether ball spawn.tetherBoss(2300, -1300, { x: 2300, y: -1750 }) if (simulation.difficulty > 4) spawn.nodeGroup(2350, -1300, "spawns", 8, 20, 105); } else { spawn.randomLevelBoss(2300, -1400, ["shooterBoss", "launcherBoss", "laserTargetingBoss", "spiderBoss", "laserBoss", "snakeBoss", "pulsarBoss"]); } } } spawn.randomSmallMob(100, -1000, 1); spawn.randomSmallMob(1340, -675, 1); spawn.randomSmallMob(7000, -3750, 1); spawn.randomSmallMob(6050, -3200, 1); spawn.randomMob(1970 + 10 * Math.random(), -1150 + 20 * Math.random(), 1); spawn.randomMob(3500, -525, 0.8); spawn.randomMob(6700, -3700, 0.8); spawn.randomMob(2600, -1300, 0.7); spawn.randomMob(600, -1250, 0.7); spawn.randomMob(2450, -250, 0.6); spawn.randomMob(6200, -3200, 0.6); spawn.randomMob(900, -700, 0.5); spawn.randomMob(1960, -400, 0.5); spawn.randomMob(5430, -3520, 0.5); spawn.randomMob(400, -700, 0.5); spawn.randomMob(6500, -4000, 0.4); spawn.randomMob(3333, -400, 0.4); spawn.randomMob(3050, -1220, 0.4); spawn.randomMob(800, 1200, 0.3); spawn.randomMob(7200, -4000, 0.3); spawn.randomMob(250, -1550, 0.3); spawn.randomGroup(900, -1450, 0.3); spawn.randomGroup(2980, -400, 0.3); spawn.randomGroup(5750, -3860, 0.4); spawn.randomGroup(1130, 1300, 0.1); powerUps.addResearchToLevel() //needs to run after mobs are spawned powerUps.spawn(1900, -940, "heal"); powerUps.spawn(3000, -230, "heal"); powerUps.spawn(5450, -3675, "ammo"); // SECRET BOSS AREA // //hidden house spawn.mapRect(-850, -2000, 600, 1150); //Toit hidden house spawn.mapRect(-2850, -2000, 2150, 4880); //Mur gauche hidden house spawn.mapRect(-850, -458, 500, 3340); //Bloc sol hidden house // spawn.mapRect(-400, 2025, 3450, 850); //Sol secret boss area spawn.mapRect(625, 1300, 225, 50); //Plateforme horizontale n°1 spawn.mapRect(850, 1775, 470, 50); //Plateforme horizontale n°2 spawn.mapRect(1000, 1625, 100, 150); //Plateforme vertiale n°1 spawn.mapRect(1400, 1275, 100, 100); //Plateforme carrée spawn.mapRect(1700, 1675, 75, 450); //Plateforme verticale n°2 spawn.mapRect(2100, 1375, 450, 50); //Plateforme accroche boss spawn.mapRect(2900, 900, 175, 325); //Débord de toit droite haut spawn.mapRect(2900, 1675, 150, 350); //Muret en bas à droite spawn.mapRect(2900, 1225, 75, 100); //Picot haut entrée salle trésor spawn.mapRect(2900, 1575, 75, 100); //Picot bas entrée salle trésor spawn.mapRect(2800, 1575, 100, 25); //Plongeoir sortie salle trésor spawn.mapRect(3050, 1675, 400, 1200); //Sol sallle trésor spawn.mapRect(3075, 1075, 375, 150); //Plafond salle trésor spawn.mapRect(3300, 1075, 1500, 1800); //Mur droite salle trésor // tether ball spawn.tetherBoss(2330, 1850, { x: 2330, y: 1425 }) spawn.secondaryBossChance(2330, 1850) //chance to spawn a ring of exploding mobs around this boss if (simulation.difficulty > 1) spawn.nodeGroup(2330, 1850, "spawns", 8, 20, 105); powerUps.chooseRandomPowerUp(3100, 1630); }, detours() { //by Francois from discord level.setPosToSpawn(0, 0); //lower start level.exit.y = 150; spawn.mapRect(level.enter.x, 45, 100, 20); level.exit.x = 10625; spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20); level.defaultZoom = 1400; simulation.zoomTransition(level.defaultZoom) document.body.style.backgroundColor = "#d5d5d5"; const BGColor = "rgba(0,0,0,0.1)"; // level.fill.push({ // x: -150, // y: -250, // width: 625, // height: 325, // color: BGColor // }); // level.fill.push({ // x: 475, // y: -520, // width: 5375, // height: 875, // color: BGColor // }); // level.fill.push({ // x: 5850, // y: -1275, // width: 2800, // height: 2475, // color: BGColor // }); // level.fill.push({ // x: 8650, // y: -500, // width: 1600, // height: 750, // color: BGColor // }); // level.fill.push({ // x: 10250, // y: -700, // width: 900, // height: 950, // color: BGColor // }); const balance = level.spinner(5500, -412.5, 25, 660) //entrance const rotor = level.rotor(7000, 580, -0.001); const doorSortieSalle = level.door(8590, -520, 20, 800, 750) // let buttonSortieSalle // let portalEnBas let portalEnHaut // let door3isClosing = false; function drawOnTheMapMapRect(x, y, dx, dy) { spawn.mapRect(x, y, dx, dy); len = map.length - 1 map[len].collisionFilter.category = cat.map; map[len].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet; Matter.Body.setStatic(map[len], true); //make static Composite.add(engine.world, map[len]); //add to world simulation.draw.setPaths() //update map graphics } function drawOnTheMapBodyRect(x, y, dx, dy) { spawn.bodyRect(x, y, dx, dy); len = body.length - 1 body[len].collisionFilter.category = cat.body; body[len].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet Composite.add(engine.world, body[len]); //add to world body[len].classType = "body" } function spawnCouloirEnHaut() { // level.fill.push({ // x: 2575, // y: -1150, // width: 2550, // height: 630, // color: BGColor // }); // level.fill.push({ // x: 1900, // y: -2300, // width: 1650, // height: 1150, // color: BGColor // }); // level.fill.push({ // x: 3550, // y: -1625, // width: 1650, // height: 475, // color: BGColor // }); // level.fill.push({ // x: 1800, // y: -1120, // width: 775, // height: 600, // color: BGColor // }); drawOnTheMapMapRect(3800, -270, 75, 75); drawOnTheMapMapRect(3900, -895, 500, 75); drawOnTheMapMapRect(3900, -1195, 75, 375); drawOnTheMapMapRect(3525, -1195, 450, 75); drawOnTheMapMapRect(3525, -1995, 50, 1575); drawOnTheMapMapRect(3325, -1995, 50, 1575); drawOnTheMapMapRect(3525, -1670, 1675, 75); drawOnTheMapMapRect(5100, -1670, 100, 1250); drawOnTheMapMapRect(1800, -1195, 1575, 75); drawOnTheMapMapRect(1800, -1520, 375, 400); drawOnTheMapMapRect(1800, -2370, 100, 1250); drawOnTheMapMapRect(2375, -1845, 375, 250); drawOnTheMapMapRect(2700, -1745, 650, 75); drawOnTheMapMapRect(1800, -2370, 1775, 100); drawOnTheMapMapRect(3525, -2370, 50, 775); drawOnTheMapMapRect(4650, -1220, 550, 75); drawOnTheMapBodyRect(3225, -1845, 100, 100); drawOnTheMapBodyRect(3575, 1255, 125, 25); drawOnTheMapBodyRect(2450, 2255, 25, 25); drawOnTheMapBodyRect(3975, -945, 175, 50); drawOnTheMapBodyRect(4825, -1295, 50, 75); drawOnTheMapBodyRect(4850, -720, 250, 200); drawOnTheMapBodyRect(4050, -970, 25, 25); drawOnTheMapBodyRect(3075, -1245, 50, 50); portalEnHaut = level.portal({ x: 3650, y: -1470 }, Math.PI / 2, { x: 3250, y: -1473 }, Math.PI / 2) spawn.randomSmallMob(2500, -2070 + Math.random(), 1); spawn.randomSmallMob(5000, -1370, 1); spawn.randomMob(5000, -645, 0.9); spawn.randomMob(4050, -970, 0.9); spawn.randomSmallMob(2800, -1620, 0.7); spawn.randomMob(2400, -1370, 0.5); spawn.randomMob(3725, -1320, 0.3); spawn.randomGroup(2115, -2020, 0.1) powerUps.spawn(5000, -1275, "heal"); levelCustom2(); } ////////////////////////////////////////// level.custom = () => { level.exit.drawAndCheck(); rotor.rotate(); // rotor2.rotate() level.enter.draw(); }; level.customTopLayer = () => { doorSortieSalle.draw(); ctx.fillStyle = "#233" ctx.beginPath(); ctx.arc(balance.pointA.x, balance.pointA.y, 9, 0, 2 * Math.PI); ctx.fill(); }; //////////////////////////////////////// function levelCustom2() { level.custom = () => { portalEnHaut[2].query(); portalEnHaut[3].query(); rotor.rotate(); doorSortieSalle.openClose(); level.exit.drawAndCheck(); level.enter.draw(); }; // ////////////////////////////////////// level.customTopLayer = () => { doorSortieSalle.draw(); portalEnHaut[0].draw(); portalEnHaut[1].draw(); portalEnHaut[2].draw(); portalEnHaut[3].draw(); ctx.fillStyle = "#233" ctx.beginPath(); ctx.arc(balance.pointA.x, balance.pointA.y, 9, 0, 2 * Math.PI); ctx.fill(); }; } //spawn box spawn.mapRect(-200, -295, 75, 425); spawn.mapRect(-200, 55, 700, 75); spawn.mapRect(-200, -295, 700, 75); spawn.bodyRect(470, -220, 25, 275); //porte spawn box //couloir spawn.mapRect(450, -520, 50, 300); //muret gauche haut spawn.mapRect(450, 55, 50, 300); //muret gauche bas spawn.mapRect(1700, -520, 50, 325); //muret 2 haut spawn.mapRect(1700, 55, 50, 300); //muret 2 bas spawn.mapRect(4375, 55, 50, 300); spawn.mapRect(4575, 55, 50, 300); spawn.bodyRect(4625, 155, 75, 100); spawn.bodyRect(4725, 230, 50, 25); if (Math.random() > 0.5) { powerUps.chooseRandomPowerUp(4500, 200); } else { powerUps.chooseRandomPowerUp(8350, -630); } //blocs spawn.bodyRect(7475, 1055, 50, 75); spawn.bodyRect(7775, 1105, 25, 25); spawn.bodyRect(6925, 1105, 125, 25); spawn.bodyRect(6375, 380, 50, 50); spawn.bodyRect(6425, -220, 125, 150); spawn.bodyRect(6475, -245, 125, 25); spawn.bodyRect(7675, -245, 100, 50); spawn.bodyRect(7075, -520, 50, 100); spawn.bodyRect(8400, -595, 100, 75); spawn.bodyRect(1700, 5, 50, 50); spawn.bodyRect(1700, -45, 50, 50); spawn.bodyRect(1700, -95, 50, 50); spawn.bodyRect(1700, -145, 50, 50); spawn.bodyRect(1700, -195, 50, 50); spawn.mapRect(450, -520, 1600, 100); //plafond 1 spawn.mapRect(450, 255, 1600, 100); //sol 1 spawn.mapRect(2250, -45, 1450, 75); //entresol spawn.mapRect(3900, -520, 2000, 100); //plafond 2 spawn.mapRect(3900, 255, 2000, 100); //sol 2 //grande salle spawn.bodyRect(5900, 830, 325, 300); //bloc en bas à gauche spawn.mapRect(5775, -1295, 2900, 100); spawn.mapRect(5775, 1130, 2900, 100); //plancher + sol grande salle spawn.mapRect(5925, -70, 650, 50); //plateforme middle entrée spawn.mapRect(7575, -520, 1100, 100); //sol salle en haut à droite spawn.mapRect(6800, -420, 450, 50); //petite plateforme transition vers salle en haut spawn.mapRect(7750, -1295, 75, 575); //mur gauche salle en haut à droite spawn.mapRect(6100, 430, 375, 50); //plateforme en bas, gauche rotor spawn.mapRect(7450, -195, 1225, 75); //longue plateforme //murs grande salle spawn.mapRect(5775, -1295, 125, 875); spawn.mapRect(5775, 255, 125, 975); spawn.mapRect(8550, -1295, 125, 875); spawn.mapRect(8550, 180, 125, 1050); //couloir 2 spawn.mapRect(8875, -520, 1425, 325); spawn.mapRect(8550, -520, 1750, 100); spawn.mapRect(8550, 180, 2625, 100); spawn.mapRect(10175, -745, 125, 325); spawn.mapRect(10175, -745, 1000, 125); spawn.mapRect(11050, -745, 125, 1025); spawn.mapRect(8875, 80, 1425, 200); //MOBS spawn.randomSmallMob(900, -70, 1); spawn.randomMob(4300, 95, 1); spawn.randomSmallMob(6250, 630, 1); spawn.randomMob(6255, -835, 0.9); spawn.randomMob(8200, -900, 0.7); spawn.randomMob(5700, -270, 0.7); spawn.randomMob(8275, -320, 0.7); spawn.randomMob(2700, -270, 0.7); spawn.randomMob(7575, 950, 0.5); spawn.randomMob(7000, -695, 0.4); spawn.randomMob(1850, -345, 0.3); spawn.randomMob(3600, -270, 0.3); spawn.randomMob(1500, -270, 0.2); spawn.randomMob(1250, 55, 0.2); spawn.randomMob(8800, -45, 0.2); spawn.randomGroup(8025, -845, 0.2); if (simulation.difficulty > 2) { // if (Math.random() < 0.2) { // // tether ball // spawn.tetherBoss(8000, 630, { x: 8550, y: 680 }) // let me = mob[mob.length - 1]; // me.onDeath = function() { //please don't edit the onDeath function this causes serious bugs // this.removeCons(); //remove constraint // spawnCouloirEnHaut() // doorSortieSalle.isClosing = false; // }; // if (simulation.difficulty > 4) spawn.nodeGroup(8000, 630, "spawns", 8, 20, 105); // } else { spawn.randomLevelBoss(8000, 630, ["shooterBoss", "launcherBoss", "laserTargetingBoss", "spiderBoss", "laserBoss", "bomberBoss", "orbitalBoss", "pulsarBoss"]); spawn.secondaryBossChance(8000, 630) //find level boss index let me for (let i = 0, len = mob.length; i < len; i++) { if (mob[i].isBoss) me = mob[i] } if (me) { me.onDeath = function() { //please don't edit the onDeath function this causes serious bugs spawnCouloirEnHaut() doorSortieSalle.isClosing = false; }; } else { spawnCouloirEnHaut() doorSortieSalle.isClosing = false; } // } } else { spawn.randomLevelBoss(8000, 630, ["shooterBoss"]); let me for (let i = 0, len = mob.length; i < len; i++) { if (mob[i].isBoss) me = mob[i] } if (me) { me.onDeath = function() { //please don't edit the onDeath function this causes serious bugs spawnCouloirEnHaut() doorSortieSalle.isClosing = false; }; } else { spawnCouloirEnHaut() doorSortieSalle.isClosing = false; } } }, house() { //by Francois from discord const rotor = level.rotor(4315, -315, -0.0002, 120, 20, 200); const hazard = level.hazard(4350, -1000, 300, 110); const doorBedroom = level.door(1152, -1150, 25, 250, 250); const doorGrenier = level.door(1152, -1625, 25, 150, 160); const buttonBedroom = level.button(1250, -850); const voletLucarne1 = level.door(1401, -2150, 20, 26, 28); const voletLucarne2 = level.door(1401, -2125, 20, 26, 53); const voletLucarne3 = level.door(1401, -2100, 20, 26, 78); const voletLucarne4 = level.door(1401, -2075, 20, 26, 103); const voletLucarne5 = level.door(1401, -2050, 20, 26, 128); const voletLucarne6 = level.door(1401, -2025, 20, 26, 153); let hasAlreadyBeenActivated = false; let grd level.setPosToSpawn(0, -50); //normal spawn spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); level.exit.x = 3100; level.exit.y = -2480; spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20); level.defaultZoom = 1800 simulation.zoomTransition(level.defaultZoom) document.body.style.backgroundColor = "rgb(170 170 170)" level.custom = () => { ctx.fillStyle = "rgb(221, 221, 221)"; ctx.fillRect(1175, -1425, 4000, 1200); ctx.fillStyle = "rgb(170 170 170)"; ctx.fillRect(1650, -1300, 175, 150); ctx.fillStyle = "rgb(77, 76, 76)"; ctx.fillRect(624, -1150, 28, 1075); ctx.fillStyle = "#ababab"; ctx.fillRect(3420, -380, 285, 40); ctx.fillStyle = "#474747"; ctx.fillRect(3555, -367.5, 15, 15); ctx.fillRect(3418, -344, 288, 8); ctx.fillRect(3555, -327.5, 15, 15); ctx.fillRect(3418, -304, 288, 8); ctx.fillRect(3555, -285, 15, 15); ctx.fillStyle = "#ababab"; ctx.fillRect(3420, -340, 285, 40); ctx.fillRect(3420, -300, 285, 45); ctx.fillStyle = "rgba(141, 141, 141,1)"; ctx.fillRect(3800, -1275, 250, 425); ctx.fillStyle = "#000"; ctx.fillRect(3800, -1275, 250, 3); ctx.fillRect(4048, -1275, 3, 425); ctx.fillRect(3800, -1275, 3, 425); ctx.fillRect(3830, -1050, 35, 10); ctx.fillStyle = "rgba(225, 242, 245,0.6)"; ctx.fillRect(4050, -1425, 1125, 600); ctx.fillStyle = "#444"; ctx.fillRect(1736, -1300, 3, 150); ctx.fillRect(1650, -1224, 175, 3); ctx.fillStyle = "#5806ac"; ctx.fillRect(3375, -625, 375, 175); ctx.fillStyle = "rgba(166, 166, 166,0.8)"; ctx.fillRect(4050, -1425, 1, 600); ctx.fillRect(4090, -1425, 1, 600); ctx.fillRect(4130, -1425, 1, 600); ctx.fillRect(4170, -1425, 1, 600); ctx.fillRect(4210, -1425, 1, 600); ctx.fillRect(4250, -1425, 1, 600); ctx.fillRect(4290, -1425, 1, 600); ctx.fillRect(4330, -1425, 1, 600); ctx.fillRect(4370, -1425, 1, 600); ctx.fillRect(4410, -1425, 1, 600); ctx.fillRect(4450, -1425, 1, 600); ctx.fillRect(4490, -1425, 1, 600); ctx.fillRect(4530, -1425, 1, 600); ctx.fillRect(4570, -1425, 1, 600); ctx.fillRect(4610, -1425, 1, 600); ctx.fillRect(4650, -1425, 1, 600); ctx.fillRect(4690, -1425, 1, 600); ctx.fillRect(4730, -1425, 1, 600); ctx.fillRect(4770, -1425, 1, 600); ctx.fillRect(4810, -1425, 1, 600); ctx.fillRect(4850, -1425, 1, 600); ctx.fillRect(4890, -1425, 1, 600); ctx.fillRect(4930, -1425, 1, 600); ctx.fillRect(4970, -1425, 1, 600); ctx.fillRect(5010, -1425, 1, 600); ctx.fillRect(5050, -1425, 1, 600); ctx.fillRect(5090, -1425, 1, 600); ctx.fillRect(5130, -1425, 1, 600); ctx.fillRect(4050, -1425, 1125, 2); ctx.fillRect(4050, -1385, 1125, 2); ctx.fillRect(4050, -1345, 1125, 2); ctx.fillRect(4050, -1305, 1125, 2); ctx.fillRect(4050, -1265, 1125, 2); ctx.fillRect(4050, -1225, 1125, 2); ctx.fillRect(4050, -1185, 1125, 2); ctx.fillRect(4050, -1145, 1125, 2); ctx.fillRect(4050, -1105, 1125, 2); ctx.fillRect(4050, -1065, 1125, 2); ctx.fillRect(4050, -1025, 1125, 2); ctx.fillRect(4050, -985, 1125, 2); ctx.fillRect(4050, -945, 1125, 2); ctx.fillRect(4050, -905, 1125, 2); ctx.fillRect(4050, -865, 1125, 2); buttonBedroom.query(); buttonBedroom.draw(); if (buttonBedroom.isUp) { if (hasAlreadyBeenActivated == false) { doorBedroom.isClosing = true; doorGrenier.isClosing = true; voletLucarne1.isClosing = true; voletLucarne2.isClosing = true; voletLucarne3.isClosing = true; voletLucarne4.isClosing = true; voletLucarne5.isClosing = true; voletLucarne6.isClosing = true; } } else { doorBedroom.isClosing = false; doorGrenier.isClosing = false; voletLucarne1.isClosing = false; voletLucarne2.isClosing = false; voletLucarne3.isClosing = false; voletLucarne4.isClosing = false; voletLucarne5.isClosing = false; voletLucarne6.isClosing = false; if (hasAlreadyBeenActivated == false) { hasAlreadyBeenActivated = true; } } doorBedroom.openClose(); doorGrenier.openClose(); voletLucarne1.openClose(); voletLucarne2.openClose(); voletLucarne3.openClose(); voletLucarne4.openClose(); voletLucarne5.openClose(); voletLucarne6.openClose(); rotor.rotate(); /// grd = ctx.createRadialGradient(512.5, -1025, 5, 512.5, -1025, 100); grd.addColorStop(0, "rgb(255, 199, 43)"); grd.addColorStop(1, "rgb(170 170 170)"); ctx.fillStyle = grd; ctx.fillRect(450, -1025, 125, 100); /// grd = ctx.createRadialGradient(762.5, -1025, 5, 762.5, -1025, 100); grd.addColorStop(0, "rgb(255, 199, 43, 1)"); grd.addColorStop(1, "rgb(170 170 170)"); ctx.fillStyle = grd; ctx.fillRect(700, -1025, 125, 100); /// ctx.lineWidth = 7; ctx.strokeStyle = "#444444" ctx.strokeRect(1650, -1300, 175, 150); chair.force.y += chair.mass * simulation.g; chair2.force.y += chair2.mass * simulation.g; person.force.y += person.mass * simulation.g; level.exit.drawAndCheck(); level.enter.draw(); }; level.customTopLayer = () => { ctx.fillStyle = "rgba(64,64,64,0.97)"; ctx.fillRect(2800, -400, 275, 175); hazard.query(); doorBedroom.draw(); doorGrenier.draw(); voletLucarne1.draw(); voletLucarne2.draw(); voletLucarne3.draw(); voletLucarne4.draw(); voletLucarne5.draw(); voletLucarne6.draw(); }; //chairs const part1 = Matter.Bodies.rectangle(4525, -255, 25, 200, { density: 0.0005, isNotHoldable: true, }); const part2 = Matter.Bodies.rectangle(4562, -235, 100, 25, { density: 0.0005, isNotHoldable: true, }); const part3 = Matter.Bodies.rectangle(4600, -202, 25, 91.5, { density: 0.0005, isNotHoldable: true, }); const part4 = Matter.Bodies.rectangle(5100, -255, 25, 200, { density: 0.0005, isNotHoldable: true, }); const part5 = Matter.Bodies.rectangle(5063, -235, 100, 25, { density: 0.0005, isNotHoldable: true, }); const part6 = Matter.Bodies.rectangle(5025, -202, 25, 91.5, { density: 0.0005, isNotHoldable: true, }); chair = Body.create({ parts: [part1, part2, part3], }); chair2 = Body.create({ parts: [part4, part5, part6], }); Composite.add(engine.world, [chair]); Composite.add(engine.world, [chair2]); composite[composite.length] = chair; composite[composite.length] = chair2; body[body.length] = part1; body[body.length] = part2; body[body.length] = part3; body[body.length] = part4; body[body.length] = part5; body[body.length] = part6; setTimeout(function() { chair.collisionFilter.category = cat.body; chair.collisionFilter.mask = cat.body | cat.player | cat.bullet | cat.mob | cat.mobBullet | cat.map }, 1000); setTimeout(function() { chair2.collisionFilter.category = cat.body; chair2.collisionFilter.mask = cat.body | cat.player | cat.bullet | cat.mob | cat.mobBullet | cat.map }, 1000); var head = Matter.Bodies.rectangle(300, -200 - 60, 34, 40, { isNotHoldable: true, }); var chest = Matter.Bodies.rectangle(300, -200, 55, 80, { isNotHoldable: true, }); var rightUpperArm = Matter.Bodies.rectangle(300 + 39, -200 - 15, 20, 40, { isNotHoldable: true, }); var rightLowerArm = Matter.Bodies.rectangle(300 + 39, -200 + 25, 20, 60, { isNotHoldable: true, }); var leftUpperArm = Matter.Bodies.rectangle(300 - 39, -200 - 15, 20, 40, { isNotHoldable: true, }); var leftLowerArm = Matter.Bodies.rectangle(300 - 39, -200 + 25, 20, 60, { isNotHoldable: true, }); var leftUpperLeg = Matter.Bodies.rectangle(300 - 20, -200 + 57, 20, 40, { isNotHoldable: true, }); var leftLowerLeg = Matter.Bodies.rectangle(300 - 20, -200 + 97, 20, 60, { isNotHoldable: true, }); var rightUpperLeg = Matter.Bodies.rectangle(300 + 20, -200 + 57, 20, 40, { isNotHoldable: true, }); var rightLowerLeg = Matter.Bodies.rectangle(300 + 20, -200 + 97, 20, 60, { isNotHoldable: true, }); //man var person = Body.create({ parts: [chest, head, leftLowerArm, leftUpperArm, rightLowerArm, rightUpperArm, leftLowerLeg, rightLowerLeg, leftUpperLeg, rightUpperLeg ], }); Composite.add(engine.world, [person]); composite[composite.length] = person body[body.length] = chest body[body.length] = head body[body.length] = part3 body[body.length] = leftLowerLeg body[body.length] = leftUpperLeg body[body.length] = leftUpperArm body[body.length] = leftLowerArm body[body.length] = rightLowerLeg body[body.length] = rightUpperLeg body[body.length] = rightLowerArm body[body.length] = rightUpperArm setTimeout(function() { person.collisionFilter.category = cat.body; person.collisionFilter.mask = cat.body | cat.player | cat.bullet | cat.mob | cat.mobBullet | cat.map }, 1000); //rez de chaussée spawn.mapRect(-200, 0, 5400, 100); //ground spawn.mapRect(1150, -255, 4050, 355); //additionnal ground spawn.mapRect(800, -255, 400, 90); //1st step spawn.mapRect(650, -170, 550, 90); //2nd step spawn.mapRect(500, -85, 700, 90); //3rd step spawn.mapRect(1150, -850, 50, 175); //porte entrée spawn.bodyRect(1162.5, -675, 25, 420) //porte entrée spawn.mapRect(1150, -850, 1500, 50); //plafond 1 spawn.mapRect(3025, -850, 2175, 50); //plafond 2 spawn.mapRect(5150, -850, 50, 650); //mur cuisine //lave-vaisselle spawn.mapRect(4225, -400, 25, 150); spawn.mapRect(4225, -400, 175, 25); spawn.mapRect(4375, -400, 25, 150); spawn.bodyRect(4350, -350, 20, 40); spawn.bodyRect(4325, -325, 20, 20); spawn.bodyRect(4325, -275, 20, 20); //escalier spawn.mapRect(3025, -850, 50, 225); spawn.mapRect(2925, -775, 150, 150); spawn.mapRect(2800, -700, 275, 75); spawn.mapRect(2575, -400, 175, 175); spawn.mapRect(2475, -325, 175, 100); spawn.mapRect(2675, -475, 400, 100); spawn.mapRect(2675, -475, 150, 250); //cuisine spawn.mapRect(4025, -850, 50, 175); //porte cuisine spawn.mapRect(4025, -375, 50, 125); //porte cuisine map[map.length] = Bodies.polygon(4050, -675, 0, 15); //circle above door spawn.bodyRect(4040, -650, 20, 260, 1, spawn.propsDoor); // door body[body.length - 1].isNotHoldable = true; //makes door swing consBB[consBB.length] = Constraint.create({ bodyA: body[body.length - 1], pointA: { x: 0, y: -130 }, bodyB: map[map.length - 1], stiffness: 1 }); Composite.add(engine.world, consBB[consBB.length - 1]); //table + chaises spawn.mapRect(4025, -850, 50, 175); spawn.mapRect(4650, -375, 325, 25); spawn.mapRect(4700, -350, 25, 100); spawn.mapRect(4900, -350, 25, 100); spawn.bodyRect(4875, -400, 75, 25); spawn.bodyRect(4700, -400, 75, 25); //murs télé spawn.mapRect(3400, -400, 20, 150); spawn.mapRect(3705, -400, 20, 150); spawn.mapRect(3400, -400, 325, 20); //socle écran spawn.mapRect(3500, -415, 125, 17); spawn.mapRect(3550, -450, 25, 50); // ??? spawn.bodyRect(3075, -375, 125, 125); spawn.bodyRect(3075, -400, 50, 25); spawn.bodyRect(3725, -325, 100, 75); spawn.bodyRect(3375, -275, 25, 25); // premier étage spawn.mapRect(1150, -1450, 4050, 50); spawn.mapRect(5150, -1450, 50, 650); spawn.mapRect(1150, -1450, 50, 300); spawn.mapRect(1150, -900, 50, 100); spawn.mapVertex(1066, -730, "-200 60 0 -60 100 -60 100 60") //chambre spawn.mapRect(2350, -1450, 50, 175); //porte chambre //lit spawn.mapRect(1475, -1025, 25, 225); //pied de lit 1 spawn.mapRect(1850, -925, 25, 125); //pied de lit 2 spawn.mapRect(1475, -925, 400, 50); //sommier spawn.bodyRect(1500, -950, 375, 25); //matelat spawn.bodyRect(1500, -1000, 75, 50); //oreiller //table spawn.bodyRect(1950, -1000, 30, 150); //pied table spawn.bodyRect(2250, -1000, 30, 150); //pied table spawn.bodyRect(1920, -1025, 390, 25); //table //salle de bain spawn.mapRect(4025, -1450, 50, 175); //porte salle de bain map[map.length] = Bodies.polygon(5050, -925, 0, 35.4); spawn.mapRect(5015, -960, 125, 40); spawn.mapRect(5050, -925, 90, 35.4); spawn.mapVertex(5086.5, -875, "100 60 -30 60 20 0 100 0") spawn.mapRect(5125, -1070, 15, 120) spawn.bodyRect(5016, -965, 108, 15) //baignoire spawn.mapVertex(4316, -965, "30 100 0 100 -80 -50 30 -50") //bord 1 spawn.mapVertex(4675, -961.5, "30 100 0 100 0 -50 80 -50") //bord 2 spawn.mapVertex(4400, -860, "0 -20 -20 20 20 20 0 -20") //pied 1 spawn.mapVertex(4600, -860, "0 -20 -20 20 20 20 0 -20") //pied 2 spawn.mapRect(4325, -900, 350, 25); //fond baignoire spawn.mapRect(4300, -1175, 25, 175); spawn.mapRect(4300, -1175, 125, 25); spawn.mapRect(4400, -1175, 25, 50); //pied pommeau de douche spawn.mapVertex(4412.5, -1105, "-20 -20 -30 40 30 40 20 -20") //pommeau de douche //grenier spawn.mapRect(1150, -1475, 50, 50); spawn.mapRect(1150, -1800, 50, 175); spawn.mapRect(5150, -1800, 50, 400); //murs spawn.mapVertex(1300, -1900, "-150 200 -200 200 50 0 100 0"); spawn.mapVertex(1800, -2300, "-150 200 -200 200 175 -100 225 -100"); spawn.mapRect(1390, -2180, 250, 30); //lucarne spawn.mapVertex(5050, -1900, "150 200 200 200 -50 0 -100 0"); spawn.mapVertex(4550, -2300, "150 200 200 200 -175 -100 -225 -100"); spawn.mapRect(4710, -2175, 250, 25); //lucarne 2 spawn.mapRect(5150, -1450, 200, 50); //obstacles spawn.mapRect(3775, -1800, 99, 50); spawn.mapRect(2425, -2150, 50, 425); spawn.mapRect(2150, -1775, 325, 50); spawn.mapRect(3825, -2150, 50, 750); spawn.mapRect(3826, -2150, 149, 50); spawn.mapRect(4125, -2150, 149, 50); spawn.mapRect(4225, -2150, 50, 450); spawn.mapRect(4225, -1750, 250, 50); level.chain(2495, -2130, 0, true, 10); spawn.bodyRect(2950, -375, 120, 120) //bloc hidden zone spawn.bodyRect(2350, -1850, 75, 75); spawn.bodyRect(4275, -1900, 75, 100); spawn.bodyRect(4825, -1650, 325, 200); spawn.bodyRect(5025, -1725, 25, 25); spawn.bodyRect(4900, -1700, 200, 75); spawn.mapVertex(2950, -2096, "-75 -50 75 -50 75 0 0 100 -75 0") /*cheminée + roof*/ spawn.mapRect(1963, -2450, 2425, 35); spawn.mapRect(2925, -2900, 125, 480); spawn.mapRect(2900, -2900, 175, 75); spawn.mapRect(2900, -2975, 25, 100); spawn.mapRect(3050, -2975, 25, 100); spawn.mapRect(2875, -3000, 225, 25); // lampadaire + jump spawn.mapRect(1000, -1450, 200, 25); spawn.mapRect(500, -1150, 275, 25); spawn.mapRect(750, -1150, 25, 75); spawn.mapRect(500, -1150, 25, 75); spawn.mapRect(450, -1075, 125, 50); spawn.mapRect(700, -1075, 125, 50); spawn.mapRect(2985, -4600, 0.1, 1700) //bodyRects ~= debris spawn.bodyRect(1740, -475, 80, 220) spawn.bodyRect(1840, -290, 38, 23) spawn.bodyRect(1200 + 1475 * Math.random(), -350, 15 + 110 * Math.random(), 15 + 110 * Math.random()); spawn.bodyRect(1200 + 1475 * Math.random(), -350, 15 + 110 * Math.random(), 15 + 110 * Math.random()); spawn.bodyRect(3070 + 600 * Math.random(), -1100, 20 + 50 * Math.random(), 150 + 100 * Math.random()) spawn.bodyRect(3050 + 1000 * Math.random(), -920, 30 + 100 * Math.random(), 15 + 65 * Math.random()); spawn.bodyRect(1600 + 250 * Math.random(), -1540, 80, 220) //boss room spawn.debris(3070, -900, 1000, 3); //16 debris per level spawn.debris(1200, -350, 1475, 4); //16 debris per level spawn.debris(1250, -1550, 3565, 9); //16 debris per level powerUps.chooseRandomPowerUp(2860, -270); // Mobs spawn.randomSmallMob(1385, -600, 1); spawn.randomSmallMob(5000, -680, 1); spawn.randomSmallMob(4750, -925, 1); spawn.randomSmallMob(2300, -1830, 1); spawn.randomMob(3170, -720, 0.8); spawn.randomMob(3700, -975, 0.8); spawn.randomMob(2625, -1150, 0.7); spawn.randomMob(4175, -750, 0.7); spawn.randomMob(2100, -370, 0.7); spawn.randomMob(2000, -1230, 0.7); spawn.randomMob(4175, -1075, 0.6); spawn.randomMob(3965, -1650, 0.6) spawn.randomMob(4650, -1750, 0.6); spawn.randomMob(830, -1170, 0.5); spawn.randomGroup(3730, -1100, 0.5); spawn.randomMob(2650, -2250, 0.3); spawn.randomMob(1615, -2270, 0.3); spawn.randomMob(1380, -1280, 0.25); spawn.randomMob(2280, -650, 0.2); spawn.randomGroup(2450, -2650, 0.2); spawn.randomMob(3800, -580, 0.2); spawn.randomMob(4630, -425, 0.1); spawn.randomGroup(630, -1300, -0.1); spawn.randomGroup(3450, -2880, -0.2) if (simulation.difficulty > 3) { spawn.secondaryBossChance(3380, -1775) if (Math.random() < 0.16) { spawn.tetherBoss(3380, -1775, { x: 3775, y: -1775 }) if (simulation.difficulty > 4) spawn.nodeGroup(3380, -1775, "spawns", 8, 20, 105); //chance to spawn a ring of exploding mobs around this boss } else { spawn.randomLevelBoss(3100, -1850, ["shooterBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss", "snakeBoss", "laserBoss"]); } } }, perplex() { //by Oranger from discord document.body.style.backgroundColor = "#dcdcde"; level.setPosToSpawn(-600, 400); spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); level.exit.x = 550; level.exit.y = -2730; spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20); const portal = level.portal({ //main portals x: -1000, y: 50 }, -Math.PI / 2, { //up x: 1000, y: 50 }, -Math.PI / 2) //up const portal2 = level.portal({ //portals in upper right corner x: 1400, y: -2200 }, -Math.PI / 2, { //up x: 1700, y: -1700 }, -Math.PI / 2) //up const rotor = level.rotor(-200, -1950, -0.001) level.custom = () => { portal[2].query(true) portal[3].query(true) portal2[2].query(true) portal2[3].query(true) rotor.rotate(); ctx.fillStyle = "#d4f4f4"; ctx.fillRect(375, -3000, 450, 300); level.exit.drawAndCheck(); level.enter.draw(); }; level.customTopLayer = () => { portal[0].draw(); portal[1].draw(); portal[2].draw(); portal[3].draw(); portal2[0].draw(); portal2[1].draw(); portal2[2].draw(); portal2[3].draw(); ctx.fillStyle = "rgba(0,0,0,0.03)"; ctx.fillRect(-875, -250, 1500, 700); ctx.fillRect(-925, -505, 930, 255); ctx.fillStyle = "rgba(0,0,0,0.1)"; ctx.fillRect(725, -1400, 200, 200); ctx.fillRect(925, -2150, 150, 2175); ctx.fillRect(925, -3400, 150, 850); ctx.fillStyle = "rgba(0,0,0,0.03)"; ctx.fillRect(1800, -2600, 400, 400); ctx.fillRect(2200, -2600, 400, 1250); }; level.defaultZoom = 1700 // 4500 // 1400 simulation.zoomTransition(level.defaultZoom) //section 1: before portals spawn.mapRect(-925, 450, 1850, 250); //1-1 base spawn.mapRect(-925, -300, 55, 755); //1 left wall spawn.mapRect(-875, 50, 1100, 50); //1-1 ceiling spawn.mapRect(620, -300, 305, 755); //1-1 and 1-2 right wall spawn.bodyRect(200, 350, 230, 100); spawn.bodyRect(300, 250, 150, 100); spawn.mapRect(-875, -300, 580, 50); //1-2 ceiling on left spawn.mapRect(0, -300, 625, 50); //1-2 ceiling on right spawn.mapRect(0, -650, 150, 350); //1-3 right wall spawn.mapRect(-925, -650, 975, 150); //1-3 ceiling spawn.mapRect(-1280, 100, 205, 150); //1-4 floor spawn.mapRect(-1280, 245, 360, 455); //bottom left corner spawn.mapRect(-1600, -200, 200, 50); //1-4 platform 1 //section 2: lower central room (gone through main portals 1 time) spawn.mapRect(920, 245, 160, 455); //below right portal spawn.mapRect(1075, -300, 500, 1000); //2-1 right floor spawn.bodyRect(100, -1000, 50, 350); spawn.bodyRect(100, -1015, 250, 15); spawn.mapRect(-925, -1600, 100, 1000); //2-2 left wall spawn.mapRect(725, -2150, 200, 750); //2-2 right wall spawn.mapRect(725, -1200, 200, 200); //2-2 right wall 2 spawn.mapRect(300, -1000, 625, 50); //2 central ledge //shute spawn.mapRect(1075, -2005, 550, 1055); //shute right wall spawn.mapRect(875, -1000, 50, 300); //shute left 1 spawn.mapRect(860, -1030, 50, 300); //shute left 2 spawn.mapRect(850, -1100, 50, 300); //shute left 3 spawn.mapRect(830, -980, 50, 50); //shute left 4 spawn.mapRect(1075, -1000, 50, 300); //shute right 1 spawn.mapRect(1090, -1030, 50, 300); //shute right 2 spawn.mapRect(1100, -1100, 50, 300); //shute right 3 spawn.mapRect(1120, -980, 50, 50); //shute right 4 spawn.mapRect(1850, -650, 400, 50); //drop from 4-1 //section 3: upper left room and upper central room (gone through main portals 2 times) //3-2 is just the upper part of 2-2 spawn.mapRect(-1775, -1000, 700, 300); //3-1 floor spawn.mapRect(-1900, -2300, 175, 1600); //3-1 left wall spawn.mapRect(-1375, -1300, 300, 50); //3-1 platform 1 spawn.mapRect(-1600, -1650, 300, 50); //3-1 platform 2 spawn.mapRect(-1775, -2300, 700, 300); //3-1 ceiling spawn.mapRect(-830, -1600, 300, 50); //3-2 left ledge spawn.mapRect(250, -2150, 675, 50); //3-2 right ledge spawn.mapRect(-925, -2300, 100, 300); //3-2 left wall spawn.mapRect(-600, -2700, 1525, 150); //3-2 ceiling spawn.mapRect(1075, -2150, 250, 150); //next to upper portal // level.fill.push({ // x: -1730, // y: -2300, // width: 870, // height: 1600, // color: "rgba(0,0,0,0.03)" // }); //section 4: upper right portals spawn.mapRect(1475, -2700, 150, 700); //4-1 left wall spawn.mapRect(1775, -1650, 250, 150); //4-1 floor-ish spawn.mapRect(1575, -1505, 450, 555); //below upper right portal spawn.mapRect(1800, -2250, 400, 50); //4-1 platform 2 spawn.bodyRect(2200, -2250, 15, 300); spawn.mapRect(2200, -1950, 400, 50); //4-1 platform 1 //spawn.bodyRect(2575, -2600, 25, 650); spawn.mapRect(2600, -1650, 400, 50); //4-1 platform 0 spawn.mapRect(2200, -1350, 400, 50); //4-1 platform -1 spawn.bodyRect(2200, -1900, 15, 550); spawn.bodyRect(2585, -1650, 15, 300); spawn.mapRect(1800, -4200, 800, 1600); //4-2 right wall spawn.mapRect(800, -4200, 1800, -500); //4-2 ceiling spawn.mapRect(1075, -3400, 225, 850); //upper shute right wall spawn.mapRect(800, -3400, 125, 850); //upper shute left wall //section 5: after portals (gone through main portals 3 times) spawn.mapRect(-700, -2700, 100, 450); //5-1 right wall spawn.mapRect(-1450, -2700, 900, 50); //5-1 ceiling spawn.mapRect(-925, -2300, 325, 50); //5-1 right floor spawn.mapRect(-1900, -3000, 450, 50); //stair cover spawn.bodyRect(-1150, -2950, 200, 250); //5-2 block //top left corner stuff spawn.mapRect(-1900, -2450, 250, 450); // //exit room spawn.mapRect(350, -3000, 50, 100); //exit room left wall spawn.mapRect(350, -3000, 450, -1700); //exit room ceiling spawn.bodyRect(350, -2900, 50, 50.5); //door spawn.bodyRect(350, -2850, 50, 50.5); //door spawn.bodyRect(350, -2800, 50, 50.5); //door spawn.bodyRect(350, -2750, 50, 50.5); //door spawn.debris(-400, 450, 400, 5); //16 debris per level spawn.debris(-1650, -2300, 250, 4); //16 debris per level spawn.debris(-750, -650, 750, 3); //16 debris per level //mobs spawn.randomMob(-650, -100, 0.7); //1-2 left spawn.randomMob(100, -150, 0.3); //1-2 right spawn.randomMob(-100, -400, 0); //1-3 right //spawn.randomMob(-1500, -300, 0.3); //1-4 platform spawn.randomMob(1450, -450, 0); //2-1 right spawn.randomMob(1700, -800, 1); //2-1 off the edge. chance is 1 because some enemies just fall spawn.randomGroup(-550, -900, -0.3); //2-2 spawn.randomMob(-1550, -1800, 0.7); //3-1 upper platform //spawn.randomMob(-1225, -1400, 0.3); //3-1 lower platform spawn.randomMob(450, -2350, 0.3); //3-2 right ledge //spawn.randomMob(1150, -2250, 0); //3-2 far right spawn.randomGroup(2400, -2300, -0.3); //4-1 floating spawn.randomMob(2400, -1450, 0); //4-1 platform -1 spawn.randomMob(2800, -1800, 0.5); //4-1 platform 0 spawn.randomMob(-1700, -3200, 0.7); //5-2 left platform spawn.randomMob(-550, -2800, 0.3); //5-2 middle if (simulation.difficulty > 3) { if (Math.random() < 0.5) { spawn.randomLevelBoss(450, -1350, ["shooterBoss", "launcherBoss", "laserTargetingBoss", "streamBoss", "shieldingBoss", "pulsarBoss", "laserBoss"]); } else { spawn.randomLevelBoss(-300, -3200, ["shooterBoss", "launcherBoss", "laserTargetingBoss", "streamBoss", "shieldingBoss", "pulsarBoss", "laserBoss"]); } } powerUps.addResearchToLevel() //needs to run after mobs are spawned spawn.secondaryBossChance(7725, 2275) }, coliseum() { level.custom = () => { level.exit.drawAndCheck(); level.enter.draw(); }; level.customTopLayer = () => {}; level.defaultZoom = 1800 simulation.zoomTransition(level.defaultZoom) document.body.style.backgroundColor = "#dcdcde"; //Level level.setPosToSpawn(200, 50); spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); level.exit.x = 8950; level.exit.y = 170; spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20); //Map spawn.mapRect(-100, -400, 100, 600); spawn.mapRect(-100, 100, 700, 100); spawn.mapRect(500, 100, 100, 1700); spawn.mapRect(500, 1700, 4000, 100); spawn.mapRect(4100, 600, 400, 100); spawn.mapRect(4400, 600, 100, 1600); spawn.mapRect(4400, 2100, 4300, 100); spawn.mapRect(8600, 200, 100, 2000); spawn.mapRect(8600, 200, 700, 100); spawn.mapRect(9200, -300, 100, 600); spawn.mapRect(8600, -300, 700, 100); spawn.mapRect(8600, -700, 100, 500); spawn.mapRect(4400, -700, 4300, 100); spawn.mapRect(4400, -700, 100, 900); spawn.mapRect(-100, -400, 4600, 100); //Platforms spawn.mapRect(1100, 400, 300, 100); spawn.mapRect(500, 500, 300, 100); spawn.mapRect(1050, 800, 300, 100); spawn.mapRect(1770, 1050, 300, 100); spawn.mapRect(1800, 500, 300, 100); spawn.mapRect(2550, 900, 300, 100); spawn.mapRect(2800, 1400, 300, 100); spawn.mapRect(1250, 1350, 300, 100); spawn.mapRect(4750, 850, 300, 100); spawn.mapRect(3200, 1050, 300, 100); spawn.mapRect(4700, 100, 300, 100); spawn.mapRect(5350, 0, 300, 100); spawn.mapRect(3800, 900, 300, 100); spawn.mapRect(5100, 500, 300, 100); spawn.mapRect(5900, -300, 300, 100); spawn.mapRect(6500, -700, 300, 1300); spawn.mapRect(7900, 0, 300, 100); spawn.mapRect(8050, 800, 300, 100); spawn.mapRect(7800, 1900, 300, 100); spawn.mapRect(8300, 450, 300, 100); spawn.mapRect(8400, 1200, 300, 100); spawn.mapRect(7570, 1100, 300, 100); spawn.mapRect(6700, 1850, 300, 100); spawn.mapRect(8000, 1500, 300, 100); spawn.mapRect(7120, -100, 300, 100); spawn.mapRect(7000, 1500, 300, 100); spawn.mapRect(6500, 1000, 300, 1200); spawn.mapRect(5800, 1100, 300, 100); spawn.mapRect(5900, 1700, 300, 100); spawn.mapRect(5300, 1400, 300, 100); spawn.mapRect(5200, 1100, 300, 100); spawn.mapRect(6700, 1100, 300, 100); spawn.mapRect(4800, 1650, 300, 100); //Room 1 Spawning spawn.randomMob(1000, 700, 0.7); spawn.randomGroup(1100, 700, 0.5); spawn.randomMob(1900, 400, 0.7); spawn.randomGroup(2000, 400, 0.4); spawn.randomGroup(1800, 1100, 0.4); spawn.randomGroup(2700, 700, 0.5); spawn.randomMob(2900, 1200, 0.7); spawn.randomSmallMob(3200, 300, 0.9); spawn.randomSmallMob(3700, 800, 0.9); spawn.randomMob(1100, 700, 0.6); spawn.randomGroup(1200, 700, 0.5); spawn.randomMob(2000, 400, 0.8); spawn.randomGroup(2100, 400, 0.5); spawn.randomGroup(1900, 1100, 0.5); spawn.randomGroup(2800, 700, 0.5); spawn.randomMob(3000, 1200, 0.7); spawn.randomSmallMob(3200, 300, 0.9); spawn.randomSmallMob(3700, 800, 0.9); spawn.randomMob(800, 1500, 0.9); spawn.randomMob(1500, 1500, 0.7); spawn.randomMob(2200, 1500, 0.6); spawn.randomMob(2500, 1500, 0.7); spawn.randomMob(2800, 1500, 0.7); spawn.randomMob(3300, 1500, 0.6); //Room 2 Spawning spawn.randomGroup(4700, 2000, 0.9); spawn.randomMob(5000, 2000, 0.5); spawn.randomSmallMob(5700, 1500, 0.9); spawn.randomMob(8500, 2000, 0.6); spawn.randomGroup(8000, 1300, 0.9); spawn.randomMob(8300, -300, 0.4); spawn.randomSmallMob(7600, -200, 0.9); spawn.randomMob(5200, -300, 0.5); spawn.randomSmallMob(4700, -200, 0.5); spawn.randomGroup(4700, 2000, 0.8); spawn.randomMob(5000, 2000, 0.5); spawn.randomSmallMob(5700, 1500, 0.9); spawn.randomGroup(8500, 2000, 0.3); spawn.randomSmallMob(8000, 1300, 0.4); spawn.randomMob(8300, -300, 0.3); spawn.randomGroup(7600, -200, 0.5); spawn.randomMob(5200, -300, 0.3); spawn.randomGroup(4700, -200, 0.4); spawn.randomGroup(8650, -200, 0.9); //end guards spawn.randomMob(8650, -200, 0.9); //end guards //Boss Spawning if (simulation.difficulty > 3) { spawn.randomLevelBoss(6000, 700, ["pulsarBoss", "laserTargetingBoss", "powerUpBoss", "bomberBoss", "historyBoss", "orbitalBoss"]); // if (simulation.difficulty > 10) spawn.shieldingBoss(7200, 500); // if (simulation.difficulty > 20) spawn.randomLevelBoss(2000, 300, ["historyBoss", "shooterBoss"]); } //Blocks spawn.bodyRect(550, -300, 50, 400); //spawn door spawn.bodyRect(4400, 200, 100, 400); //boss door spawn.bodyRect(6600, 600, 50, 400); //boss 2 door spawn.debris(400, 800, 400, 2); spawn.debris(3800, 1600, 1200, 6); spawn.debris(7500, 2000, 800, 4); spawn.debris(5500, 2000, 800, 4); //Powerups powerUps.spawnStartingPowerUps(1250, 1500); // powerUps.spawnStartingPowerUps(1500, 1500); powerUps.spawn(8650, -200, "ammo"); // powerUps.spawn(8650, -200, "ammo"); // powerUps.spawn(8650, -200, "ammo"); // powerUps.spawn(8650, -200, "ammo"); powerUps.spawn(200, 50, "heal"); // powerUps.spawn(200, 50, "ammo"); // powerUps.spawn(200, 50, "ammo"); // powerUps.spawn(200, 50, "ammo"); powerUps.addResearchToLevel() //needs to run after mobs are spawned spawn.secondaryBossChance(6600, 600) }, crossfire() { //*1.5 //Level Setup const slimePitOne = level.hazard(0, 850, 3800, 120); const slimePitTwo = level.hazard(4600, 430, 2000, 120); const slimePitThree = level.hazard(6500, 200, 1000, 170); level.custom = () => { level.exit.drawAndCheck(); level.enter.draw(); }; level.customTopLayer = () => { slimePitOne.query(); slimePitTwo.query(); slimePitThree.query(); }; level.setPosToSpawn(-500, 550); //normal spawn spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); level.exit.x = 10300; level.exit.y = -830; spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20); level.defaultZoom = 3000 simulation.zoomTransition(level.defaultZoom) document.body.style.backgroundColor = "#dcdcde"; //Map Elements spawn.mapRect(-800, -600, 800, 200); spawn.mapRect(-200, -600, 200, 800); spawn.mapRect(-800, -600, 200, 800); spawn.mapRect(-1000, 0, 1000, 200); spawn.mapRect(-1000, 0, 200, 800); spawn.mapRect(-1000, 600, 1400, 200); spawn.mapRect(0, 600, 200, 400); spawn.mapRect(0, 950, 4000, 100); spawn.mapRect(800, 800, 600, 200); spawn.mapRect(1700, 700, 500, 300); spawn.mapRect(2500, 600, 400, 400); spawn.mapRect(3200, 600, 1200, 200); spawn.mapRect(3800, 600, 200, 800); // spawn.mapRect(3800, 1200, 800, 200); spawn.mapRect(4400, 400, 300, 1000); spawn.mapRect(4400, 500, 2000, 100); spawn.mapRect(6500, 300, 1000, 100); spawn.mapRect(5000, 200, 700, 400); spawn.mapRect(6000, 0, 650, 600); spawn.mapRect(6900, -300, 700, 100); spawn.mapRect(7400, -600, 200, 1100); spawn.mapRect(7400, 300, 2600, 200); spawn.mapRect(9800, -800, 200, 1300); spawn.mapRect(9800, -800, 1000, 200); spawn.mapRect(10600, -1400, 200, 800); spawn.mapRect(9800, -1400, 200, 400); spawn.mapRect(7400, -1400, 3400, 200); spawn.mapRect(7400, -1600, 200, 800); spawn.mapRect(5400, -1600, 2200, 200); spawn.mapRect(6000, -1600, 200, 800); spawn.mapRect(5400, -1600, 200, 800); spawn.mapRect(4800, -1000, 1400, 200); spawn.mapRect(4800, -1000, 200, 600); spawn.mapRect(3800, -600, 1200, 200); spawn.mapRect(3200, -800, 800, 200); spawn.mapRect(3200, -800, 200, 800); spawn.mapRect(3800, -800, 200, 800); spawn.mapRect(-200, -200, 4200, 200); //Boss Room Platforms spawn.mapRect(7700, 100, 300, 40); spawn.mapRect(8600, 0, 300, 40); spawn.mapRect(9200, 100, 300, 40); spawn.mapRect(9400, -200, 300, 40); spawn.mapRect(8000, -200, 300, 40); spawn.mapRect(8500, -400, 300, 40); spawn.mapRect(9000, -600, 300, 40); spawn.mapRect(9400, -800, 300, 40); spawn.mapRect(8600, -1000, 300, 40); spawn.mapRect(7900, -800, 300, 40); //Mob Spawning spawn.randomMob(200, 400, 0.7); // spawn.randomMob(1200, 400, 0.7); spawn.randomMob(2000, 400, 0.7); // spawn.randomMob(3000, 400, 0.7); spawn.randomMob(5000, 0, 0.7); spawn.randomMob(5600, 0, 0.7); spawn.randomMob(6200, -200, 0.7); // spawn.randomMob(6600, -200, 0.7); spawn.randomMob(7200, -800, 0.7); spawn.randomSmallMob(800, 400, 0.9); spawn.randomSmallMob(1800, 400, 0.9); // spawn.randomSmallMob(2600, 400, 0.9); spawn.randomSmallMob(5200, 0, 0.9); // spawn.randomSmallMob(5400, 0, 0.9); spawn.randomSmallMob(6400, -200, 0.9); spawn.randomGroup(3800, 400, 0.5); spawn.randomGroup(4200, 400, 0.5); // spawn.randomGroup(4400, 200, 0.5); spawn.randomGroup(7000, -800, 0.5); // spawn.randomGroup(7700, 300, 0.5); spawn.randomGroup(9800, 300, 0.5); // spawn.randomGroup(7700, -1100, 0.5); spawn.randomGroup(9800, -1100, 0.5); if (simulation.difficulty > 3) spawn.randomLevelBoss(8600, -600, ["powerUpBoss", "bomberBoss", "snakeBoss", "spiderBoss", "historyBoss"]) spawn.secondaryBossChance(7900, -400) //Boss Spawning if (simulation.difficulty > 10) { spawn.pulsarBoss(3600, -400); powerUps.chooseRandomPowerUp(4006, 400); powerUps.chooseRandomPowerUp(4407, 400); powerUps.spawnStartingPowerUps(4400, 400); if (simulation.difficulty > 30) { powerUps.chooseRandomPowerUp(4002, 400); powerUps.chooseRandomPowerUp(4004, 400); spawn.pulsarBoss(4200, 1000); if (simulation.difficulty > 60) { powerUps.chooseRandomPowerUp(4409, 400); spawn.pulsarBoss(5800, -1200); if (simulation.difficulty > 80) { spawn.pulsarBoss(-400, -200); if (simulation.difficulty > 100) { spawn.pulsarBoss(3600, -400); if (simulation.difficulty > 120) { spawn.pulsarBoss(-400, -200); } } } } } } //Powerup Spawning powerUps.spawnStartingPowerUps(4000, 400); powerUps.addResearchToLevel(); //needs to run after mobs are spawned //Block Spawning // spawn.bodyRect(-100, 200, 100, 400); //spawn door spawn.bodyRect(7450, -800, 25, 200); //boss room door spawn.bodyRect(9850, -1000, 25, 200); //end door spawn.mapRect(-200, 350, 200, 450); // spawn.mapRect(3875, -75, 50, 575); spawn.mapRect(3800, -75, 200, 525); spawn.mapRect(3875, 590, 50, 150); spawn.mapRect(3875, 350, 50, 140); const debrisCount = 3 spawn.debris(1050, 700, 400, debrisCount); spawn.debris(1900, 600, 400, debrisCount); spawn.debris(2700, 500, 400, debrisCount); // spawn.debris(3500, 450, 400, debrisCount); spawn.debris(4150, 500, 400, debrisCount); spawn.debris(5300, 0, 400, debrisCount); spawn.debris(6300, -100, 400, debrisCount); spawn.debris(7200, -500, 400, debrisCount); spawn.debris(8000, -600, 400, debrisCount); spawn.debris(8700, -700, 400, debrisCount); spawn.debris(9300, -900, 400, debrisCount); }, vats() { // Made by Dablux#6610 on Discord simulation.zoomScale = 1500; level.setPosToSpawn(4400, -1060) spawn.mapRect(level.enter.x, level.enter.y + 30, 100, 20) level.exit.x = 3900; level.exit.y = 1060; spawn.mapRect(level.exit.x, level.exit.y + 30, 100, 20) document.body.style.backgroundColor = "#dcdcde"; var nextBlockSpawn = simulation.cycle + Math.floor(Math.random() * 60 + 30) const door = level.door(475, 900, 50, 200, 201) const exitDoor = level.door(3375, 900, 50, 200, 201) const deliveryButton = level.button(3500, -410) const buttonGreen = level.button(-1600, 1090) const buttonYellow = level.button(-1600, -1160) const buttonRed = level.button(5874, -2410) let g = false; let y = false; let r = false; const deliverySlime = level.hazard(3700, -940, 100, 480) const deliverySlime2 = level.hazard(3700, -461, 100, 1141) const slimePit = level.hazard(700, 1200, 2500, 1300, 0.004, "hsla(160, 100%, 35%,0.75)") const topSlime = level.hazard(800, -460, 2900, 90, 0.004, "hsla(160, 100%, 35%,0.75)") const rotor = level.rotor(0, -725, 0.001) const portal = level.portal({ x: -135, y: 800 }, Math.PI / 2, { x: 570, y: -395 }, -Math.PI / 2) const portal2 = level.portal({ x: -1800, y: 1900 }, Math.PI, { x: 200, y: 1105 }, -Math.PI / 2) const drip1 = level.drip(1875, -660, -400, 70) const drip2 = level.drip(3525, -940, -400, 150) const drip3 = level.drip(1975, 100, 1200, 100) door.isClosing = true; exitDoor.isClosing = true; // UPPER AREA // spawn.mapRect(4500, -2400, 1700, 2050) spawn.mapRect(3800, -1000, 700, 650) spawn.mapRect(4000, -1310, 50, 60) spawn.mapRect(4450, -1310, 50, 60) spawn.mapRect(4000, -1320, 500, 20) level.chain(4025, -1225, 0.5 * Math.PI, false, 5, 25) spawn.mapRect(3650, -460, 50, 90) spawn.mapRect(3525, -1000, 325, 20) spawn.mapRect(3650, -1000, 50, 440) spawn.mapRect(3300, -1000, 50, 450) spawn.mapRect(3325, -725, 150, 25) spawn.mapRect(3500, -980, 175, 35) spawn.mapRect(3325, -980, 50, 35) spawn.mapRect(-1800, -1250, 50, 120) spawn.mapRect(6150, -2500, 50, 120) spawn.bodyRect(3350, -1000, 175, 20, 1, spawn.propsIsNotHoldable) // Cover Matter.Body.setMass(body[body.length - 1], 0.7) // Make cover easier to remove spawn.mapRect(750, -475, 50, 75); for (let i = 1; i < 5; i++) { spawn.mapRect(800 + (i * 100) + (500 * (i - 1)), -460 + (i * -120) + (20 * (i - 1)), 500, 20) } // ARENA // spawn.mapRect(400, -400, 2950, 500) spawn.mapRect(-1800, -1150, 1800, 1950) spawn.mapRect(-1800, 1100, 780, 1800) spawn.mapRect(-300, 1100, 1000, 1800) //spawn.mapRect(-1800, -1450, 100, 2000) spawn.blockDoor(-1800, 1070) level.chain(-1000, 1120, 0, true, 18, 20) spawn.mapRect(700, 2500, 2500, 900) spawn.mapRect(400, 100, 200, 599) spawn.mapRect(400, 650, 75, 250) spawn.mapRect(525, 650, 75, 250) spawn.mapRect(3300, 650, 75, 250) spawn.mapRect(3425, 650, 75, 250) spawn.mapRect(3200, 1100, 1800, 2200) spawn.mapRect(3300, -400, 200, 1099) // STOP CHANGING THIS ONE!!!! spawn.mapRect(3450, -400, 250, 1100) spawn.mapRect(3650, 680, 200, 20) spawn.mapRect(3800, -400, 1400, 1100) spawn.mapRect(4100, 700, 100, 300) spawn.mapRect(4900, -400, 1300, 2500) spawn.bodyRect(4100, 1000, 100, 100) spawn.bodyRect(-2100, 2050, 290, 30) //Portal platform let b = body[body.length - 1]; cons[cons.length] = Constraint.create({ pointA: { x: -1820, y: 2065 }, bodyB: b, pointB: { x: -135, y: 0 }, stiffness: 1, length: 1 }); cons[cons.length] = Constraint.create({ pointA: { x: -1800, y: 1400 }, bodyB: b, pointB: { x: 135, y: 0 }, stiffness: 0.005, length: 700 }); Composite.add(engine.world, [cons[cons.length - 2], cons[cons.length - 1]]); spawn.bodyRect(5225, -2525, 300, 75); spawn.bodyRect(4700, -2525, 100, 75, 0.5); spawn.bodyRect(4900, -2600, 50, 50, 0.4); spawn.bodyRect(5050, -2475, 500, 100, 0.4); spawn.bodyRect(2950, -950, 175, 75, 0.5); spawn.bodyRect(3050, -1000, 75, 50, 0.3); spawn.bodyRect(2300, -850, 75, 50, 0.7); spawn.bodyRect(2150, -575, 100, 175, 0.6); spawn.bodyRect(2500, -550, 400, 150, 0.2); spawn.bodyRect(1525, -500, 225, 100, 0.2); spawn.bodyRect(1625, -575, 100, 75); spawn.bodyRect(1000, -475, 100, 100, 0.8); spawn.bodyRect(1225, -450, 125, 50, 0.9); spawn.bodyRect(525, -500, 175, 125, 0.75); spawn.bodyRect(575, -600, 100, 75, 0.5); spawn.bodyRect(-925, -1225, 275, 75, 0.4); spawn.bodyRect(-1125, -1300, 200, 150, 0.7); spawn.bodyRect(-475, -1250, 200, 100, 0.8); spawn.bodyRect(-425, -1300, 100, 50, 0.75); spawn.bodyRect(-1225, -1200, 100, 25, 0.45); spawn.bodyRect(-1025, -1350, 75, 50, 0.5); spawn.bodyRect(-450, 1025, 75, 50, 0.5); spawn.bodyRect(-775, 1050, 50, 50, 0.6); spawn.bodyRect(-650, 975, 75, 75, 0.2); spawn.bodyRect(-475, 1025, 100, 50, 0.7); spawn.bodyRect(-450, 1025, 75, 50, 0.6); spawn.bodyRect(-800, 1050, 100, 50, 0.5); spawn.bodyRect(-600, 950, 75, 75, 0.3); spawn.bodyRect(-500, 1000, 75, 25, 0.2); spawn.bodyRect(-900, 1025, 150, 50); spawn.bodyRect(-1350, 1000, 100, 100, 0.4); spawn.bodyRect(-1225, 1075, 100, 25); spawn.debris(900, -1000, 2000, 16); // MOBS // spawn.randomSmallMob(2900, -1000) spawn.randomSmallMob(1750, -700) spawn.randomMob(4250, -1400) spawn.randomMob(4800, -2400, 0.3) spawn.randomMob(1000, 600, 0.3) spawn.randomMob(1650, 950, 0.2) spawn.randomMob(1300, -1250, 0) spawn.randomMob(-600, -1250, 0.1) spawn.randomMob(1000, -600, 0.4) spawn.randomMob(1800, -700, 0.4) spawn.randomMob(2200, 950, 0.2) spawn.randomMob(-1900, 1400, 0.3) spawn.randomMob(-750, -1000, 0.3) spawn.randomMob(3250, 1000, 0.1) spawn.randomMob(2000, -2800, 0.4) spawn.randomMob(2200, -500, 0) spawn.randomMob(1800, -450, 0.3) spawn.randomGroup(2300, -450, 1) spawn.randomGroup(3000, -450, 0.3) spawn.randomGroup(6000, -2700, 0) spawn.randomGroup(-1200, -1300, -0.3) powerUps.addResearchToLevel() if (simulation.difficulty > 3) { spawn.randomLevelBoss(1900, 400, ["shieldingBoss", "shooterBoss", "launcherBoss", "streamBoss"]) } else { exitDoor.isClosing = false; } spawn.secondaryBossChance(800, -800) powerUps.spawn(4450, 1050, "heal"); if (Math.random() > (0.2 + (simulation.difficulty / 60))) { powerUps.spawn(4500, 1050, "ammo"); powerUps.spawn(4550, 1050, "ammo"); } else { powerUps.spawn(4500, 1050, "tech"); spawn.randomMob(4550, 1050, Infinity); } powerUps.spawnStartingPowerUps(3750, -940) const W = 500; const H = 20; for (let i = 1; i < 5; i++) { spawn.bodyRect(700 + (i * 100) + (W * (i - 1)), 1110, W, H, 1, spawn.propsIsNotHoldable) let b = body[body.length - 1]; cons[cons.length] = Constraint.create({ pointA: { x: b.position.x - (W / 2) + 50, y: b.position.y - 1025 }, bodyB: b, pointB: { x: -(W / 2) + 50, y: 0 }, stiffness: 0.002, length: 1000 }); cons[cons.length] = Constraint.create({ pointA: { x: b.position.x + (W / 2) - 50, y: b.position.y - 1025 }, bodyB: b, pointB: { x: (W / 2) - 50, y: 0 }, stiffness: 0.002, length: 1000 }); Composite.add(engine.world, [cons[cons.length - 1], cons[cons.length - 2]]) } const boost1 = level.boost(4400, -1385, 1200) level.custom = () => { boost1.query(); buttonGreen.query() buttonYellow.query() buttonRed.query() if (!buttonGreen.isUp) { if (!g) { Matter.Composite.remove(engine.world, cons[1]) cons.splice(1, 2) } g = true; } if (!buttonYellow.isUp) { y = true; } if (!buttonRed.isUp) { r = true; } if (g && y && r) { door.isClosing = false; } else { door.isClosing = true; } door.openClose() exitDoor.openClose() if (m.pos.y > 1600 && 700 < m.pos.x && m.pos.x < 3200) { // Saving player from slime pit Matter.Body.setVelocity(player, { x: 0, y: 0 }); Matter.Body.setPosition(player, { x: 200, y: 1000 }); // move bots for (let i = 0; i < bullet.length; i++) { if (bullet[i].botType) { Matter.Body.setPosition(bullet[i], Vector.add(player.position, { x: 250 * (Math.random() - 0.5), y: 250 * (Math.random() - 0.5) })); Matter.Body.setVelocity(bullet[i], { x: 0, y: 0 }); } } m.damage(0.1 * simulation.difficultyMode) m.energy -= 0.1 * simulation.difficultyMode } if (simulation.cycle >= nextBlockSpawn && body.length < 100) { var len = body.length; body[len] = Matter.Bodies.polygon(Math.floor(Math.random() * 1700) + 1050, 100, Math.floor(Math.random() * 11) + 10, Math.floor(Math.random() * 20) + 15) body[len].collisionFilter.category = cat.body; body[len].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet; Composite.add(engine.world, body[len]) nextBlockSpawn = simulation.cycle + Math.floor(Math.random() * 60 + 30) } if (exitDoor.isClosing) { exitDoor.isClosing = false; for (i = 0; i < mob.length; i++) { if (mob[i].isBoss && 525 < mob[i].position.x < 3200 && -2500 < mob[i].position.y < 100) { exitDoor.isClosing = true; } } } for (let i = 0, len = body.length; i < len; i++) { if (body[i].position.x > 700 && body[i].position.x < 3200 && body[i].position.y > 1200 && !body[i].isNotHoldable) { Matter.Body.scale(body[i], 0.99, 0.99); if (body[i].velocity.y > 3) body[i].force.y -= 0.96 * body[i].mass * simulation.g const slowY = (body[i].velocity.y > 0) ? Math.max(0.3, 1 - 0.0015 * body[i].velocity.y * body[i].velocity.y) : Math.max(0.98, 1 - 0.001 * Math.abs(body[i].velocity.y)) //down : up Matter.Body.setVelocity(body[i], { x: Math.max(0.6, 1 - 0.07 * Math.abs(body[i].velocity.x)) * body[i].velocity.x, y: slowY * body[i].velocity.y }); if (body[i].mass < 0.05) { Matter.Composite.remove(engine.world, body[i]) body.splice(i, 1) break } } } for (let i = 0, len = mob.length; i < len; ++i) { if (mob[i].position.x > 700 && mob[i].position.x < 3200 && mob[i].alive && !mob[i].isShielded && mob[i].position.y > 1200) { mobs.statusDoT(mob[i], 0.005, 30) } } ctx.beginPath() ctx.fillStyle = "#666"; ctx.arc(buttonGreen.min.x - 50, buttonGreen.min.y - 70, 20, 0, 2 * Math.PI) ctx.fillRect(buttonGreen.min.x - 55, buttonGreen.max.y + 25, 10, -95) ctx.fill() ctx.beginPath() ctx.arc(buttonYellow.min.x - 50, buttonYellow.min.y - 70, 20, 0, 2 * Math.PI) ctx.fillRect(buttonYellow.min.x - 55, buttonYellow.max.y + 25, 10, -95) ctx.fill() ctx.beginPath() ctx.arc(buttonRed.min.x - 50, buttonRed.min.y - 70, 20, 0, 2 * Math.PI) ctx.fillRect(buttonRed.min.x - 55, buttonRed.max.y + 25, 10, -95) ctx.fill() ctx.beginPath() ctx.arc(buttonGreen.min.x - 50, buttonGreen.min.y - 70, 10, 0, 2 * Math.PI) ctx.fillStyle = (g ? `rgba(0, 255, 0, 0.9)` : `rgba(255, 0, 0, 0.9)`); ctx.fill() ctx.beginPath() ctx.arc(buttonYellow.min.x - 50, buttonYellow.min.y - 70, 10, 0, 2 * Math.PI) ctx.fillStyle = (y ? `rgba(0, 255, 0, 0.9)` : `rgba(255, 0, 0, 0.9)`); ctx.fill() ctx.beginPath() ctx.arc(buttonRed.min.x - 50, buttonRed.min.y - 70, 10, 0, 2 * Math.PI) ctx.fillStyle = (r ? `rgba(0, 255, 0, 0.9)` : `rgba(255, 0, 0, 0.9)`); ctx.fill() slimePit.query(); ctx.shadowColor = 'hsla(160, 100%, 50%, 1)' ctx.shadowBlur = 100; // slimePit.draw() ctx.shadowBlur = 0; ctx.shadowColor = 'rgba(0, 0, 0, 0)' deliveryButton.query() portal[2].query() //portal[3].query() portal2[2].query() //portal2[3].query() deliverySlime.level(deliveryButton.isUp) topSlime.level(!r) rotor.rotate() ctx.fillStyle = "#d4f4f4" ctx.fillRect(3500, 675, 600, 450) level.enter.draw() level.exit.drawAndCheck() } level.customTopLayer = () => { topSlime.query(); deliverySlime.query() deliverySlime2.query() drip1.draw() drip2.draw() drip3.draw() ctx.fillStyle = `rgba(68, 68, 68, ${Math.max(0.3, Math.min((4200 - m.pos.x) / 100, 0.99))})` ctx.fillRect(4100, 650, 850, 500) ctx.fillStyle = "rgba(0,20,40,0.1)" ctx.fillRect(4025, -1300, 475, 300) ctx.fillRect(3325, -1000, 375, 600) ctx.fillRect(425, 100, 3050, 2400) ctx.fillRect(-1775, 800, 1750, 2100) ctx.fillStyle = "rgba(0,20,40,0.2)" ctx.fillRect(2725, -860, 450, 460) ctx.fillRect(2125, -760, 450, 360) ctx.fillRect(1525, -660, 450, 260) ctx.fillRect(925, -560, 450, 160) ctx.fillRect(3700, -980, 100, 1200) ctx.fillStyle = `#444`; ctx.fillRect(465, 690, 70, 209) ctx.fillRect(3365, 690, 70, 209) ctx.beginPath() ctx.arc(500, 870, 20, 0, 2 * Math.PI) ctx.arc(500, 820, 20, 0, 2 * Math.PI) ctx.arc(500, 770, 20, 0, 2 * Math.PI) ctx.fillStyle = "rgba(0, 0, 0, 0.3"; ctx.fill() ctx.beginPath() ctx.arc(500, 870, 10, 0, 2 * Math.PI) ctx.fillStyle = (g ? `rgba(0, 255, 0, 0.9)` : `rgba(255, 0, 0, 0.9)`); ctx.fill() ctx.beginPath() ctx.arc(500, 820, 10, 0, 2 * Math.PI) ctx.fillStyle = (y ? `rgba(0, 255, 0, 0.9)` : `rgba(255, 0, 0, 0.9)`); ctx.fill() ctx.beginPath() ctx.arc(500, 770, 10, 0, 2 * Math.PI) ctx.fillStyle = (r ? `rgba(0, 255, 0, 0.9)` : `rgba(255, 0, 0, 0.9)`); ctx.fill() deliveryButton.draw() // deliverySlime.draw() // deliverySlime2.draw() // topSlime.draw() buttonGreen.draw() buttonYellow.draw() buttonRed.draw() portal[0].draw() portal[2].draw() portal2[0].draw() portal2[2].draw() } }, "n-gon"() { //make by Oranger document.body.style.backgroundColor = "#dcdcde"; let needGravity = []; let s = { //mech statue x: -200, y: -2350, angle: 0, scale: 15, h: { //hip x: 12, y: 24 }, k: { //knee x: -30.96, //-17.38 y: 58.34, //70.49 //x2: -33.96, //x - 3 //y2: 58.34 //same as y }, f: { //foot x: 0, y: 91 //112 }, fillColor: "#ccc", //white fillColorDark: "#bbb", //25% from white lineColor: "#999", //#333 lineColorLight: "#aaa" //#4a4a4a } const boost1 = level.boost(2550, 1500, 1700) const boost2 = level.boost(-3400, -2050, 2100) level.custom = () => { boost1.query(); boost2.query(); level.exit.drawAndCheck(); level.enter.draw(); for (let i = 0; i < needGravity.length; i++) { needGravity[i].force.y += needGravity[i].mass * simulation.g; } ctx.fillStyle = "#444" //light fixtures ctx.fillRect(2350, 995, 40, 10) //ctx.fillRect(2280, -6005, 40, 10) //statue ctx.save(); ctx.translate(s.x, s.y); //statueLeg is at the bottom, below the enemies but above the NGON function statueLeg(-3, s.lineColorLight); statueLeg(0, s.lineColor); //head ctx.rotate(s.angle); ctx.beginPath(); ctx.arc(0, 0, 30 * s.scale, 0, 2 * Math.PI); let grd = ctx.createLinearGradient(-30 * s.scale, 0, 30 * s.scale, 0); grd.addColorStop(0, s.fillColorDark); grd.addColorStop(1, s.fillColor); ctx.fillStyle = grd; ctx.fill(); ctx.arc(15 * s.scale, 0, 4 * s.scale, 0, 2 * Math.PI); ctx.strokeStyle = s.lineColor; ctx.lineWidth = 2 * s.scale; ctx.stroke(); ctx.restore(); }; level.customTopLayer = () => { //boost chute for lack of a better name ctx.fillStyle = "rgba(60,60,60,0.9)"; ctx.fillRect(-3451, -4000, 202, 1500); ctx.fillRect(2499, -170, 202, 1170); ctx.fillStyle = "rgba(0,0,0,0.2)"; ctx.beginPath(); //basement ctx.moveTo(2360, 1000); ctx.lineTo(2120, 900); ctx.lineTo(1500, 900); ctx.lineTo(1500, 1500); ctx.lineTo(3000, 1500); ctx.lineTo(3000, 1000); ctx.lineTo(2380, 1000); ctx.lineTo(2870, 1500); ctx.lineTo(1870, 1500); ctx.lineTo(2360, 1000); ctx.fill(); // ctx.beginPath(); //exit // ctx.moveTo(1600, -6000); // ctx.lineTo(1600, -5000); // ctx.lineTo(3000, -5000); // ctx.lineTo(3000, -6000); // ctx.lineTo(2310, -6000); // ctx.lineTo(2600, -5000); // ctx.lineTo(2000, -5000); // ctx.lineTo(2290, -6000); // ctx.lineTo(1600, -6000); // ctx.fill(); ctx.fillStyle = "rgba(0,0,0,0.3)"; ctx.fillRect(1600, -1000, 1400, 830); ctx.fillRect(1600, -170, 520, 170); ctx.fillRect(-1300, -200, 2200, 200); //statue base ctx.fillRect(-800, -400, 1200, 200); ctx.fillRect(-500, -700, 600, 300); //ctx.fillRect(-4000, -6000, 2000, 1000); //left side ctx.fillRect(-4000, -2500, 2000, 2500); }; level.setPosToSpawn(1810, 1450); spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); level.exit.x = 2700; level.exit.y = -4030; spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20); level.defaultZoom = 3500 simulation.zoomTransition(level.defaultZoom) // powerUps.spawnStartingPowerUps(1475, -1175); spawn.debris(2750, 1500, 200, 4); //16 debris per level spawn.debris(1770, -350, 120, 4); //16 debris per level spawn.debris(-3200, 0, 1000, 6); //16 debris per level //boundaries spawn.mapRect(-4100, 1500, 7200, 100); //base floor spawn.mapRect(3000, -4000, 100, 5600); //right barrier spawn.mapRect(-4100, -4000, 100, 5600); //left barrier //spawn.mapRect(1600, -10000, 1500, 4000); //upper right wall //spawn.mapRect(-4100, -10000, 2100, 4000); //upper left wall spawn.mapRect(1600, -4000, 1500, 3000); //right wall spawn.mapRect(-4100, 0, 5600, 1550); //floor //starting room spawn.mapRect(1500, 0, 700, 900); spawn.mapRect(2120, -170, 380, 1170); spawn.mapRect(2700, -170, 400, 1170); //spawn.mapVertex(2296, 400, "0 0 0 1200 300 1200 400 0"); //spawn.mapVertex(2904, 400, "0 0 0 1200 -300 1200 -400 0"); //left area spawn.mapRect(-3500, -300, 300, 400); //floor 1 spawn.mapRect(-3900, -600, 300, 100); spawn.mapRect(-3500, -900, 300, 100); spawn.mapRect(-3100, -1150, 1000, 150); //floor 2 spawn.mapRect(-2200, -2600, 200, 1600); spawn.mapRect(-2700, -1450, 300, 100); spawn.mapRect(-3100, -1750, 300, 100); spawn.mapRect(-3500, -2050, 300, 100); spawn.mapRect(-4100, -4000, 650, 1500); //floor 3 spawn.mapRect(-3250, -4000, 1250, 1500); //statue base spawn.mapRect(-700, -900, 1000, 200); //top //left spawn.mapRect(-700, -900, 200, 500); spawn.mapRect(-1000, -600, 500, 200); spawn.mapRect(-1000, -600, 200, 400); spawn.mapRect(-1300, -300, 500, 100); //right spawn.mapRect(100, -900, 200, 500); spawn.mapRect(100, -600, 500, 200); spawn.mapRect(400, -600, 200, 400); spawn.mapRect(400, -300, 500, 100); hangingNGON(-1900, -4000, 1, 1000, 1, false, { density: 0.001, //default density is 0.001 friction: 0.0001, frictionAir: 0.001, frictionStatic: 0, restitution: 0, isNotHoldable: true }); hangingNGON(1900, -4600, 0.2, 300, 0.0005, false, { density: 0.00005, //default density is 0.001 friction: 0.0001, frictionAir: 0.003, frictionStatic: 0, restitution: 1, isNotHoldable: true }); // // Never gonna give you up // spawn.bodyRect(-8000, -10100, 15, 100); // // Never gonna let you down // spawn.bodyRect(-7915, -10100, 15, 100); // // Never gonna run around and desert you // body[body.length] = Bodies.polygon(-7950, -10025, 0, 25, { //circle // friction: 0.05, // frictionAir: 0.001 // }); // // Never gonna make you cry // spawn.bodyRect(6985, -10100, 15, 100); // // Never gonna say goodbye // spawn.bodyRect(6900, -10100, 15, 100); // // Never gonna tell a lie and hurt you // body[body.length] = Bodies.polygon(6950, -10025, 0, 25, { //circle // friction: 0.05, // frictionAir: 0.001 // }); //pile of blocks spawn.bodyRect(1920, -400, 200, 400) spawn.bodyRect(1720, -250, 200, 250) spawn.bodyRect(1770, -300, 150, 50) spawn.bodyRect(2120, -280, 100, 100) spawn.bodyRect(1990, -500, 100, 100) //doors under statue spawn.bodyRect(850, -50, 50, 50) spawn.bodyRect(850, -100, 50, 50) spawn.bodyRect(850, -150, 50, 50) spawn.bodyRect(850, -200, 50, 50) spawn.bodyRect(-1300, -50, 50, 50) spawn.bodyRect(-1300, -100, 50, 50) spawn.bodyRect(-1300, -150, 50, 50) spawn.bodyRect(-1300, -200, 50, 50) // on the statue base spawn.randomMob(700 + Math.random() * 100, -500 + Math.random() * 100, 1); spawn.randomMob(400 + Math.random() * 100, -800 + Math.random() * 100, 0.4); spawn.randomMob(100 + Math.random() * 100, -1100 + Math.random() * 100, -0.2); spawn.randomGroup(-200, -1400, -0.4); spawn.randomMob(-600 + Math.random() * 100, -1100 + Math.random() * 100, -0.2); spawn.randomMob(-900 + Math.random() * 100, -800 + Math.random() * 100, 0.4); spawn.randomMob(-1200 + Math.random() * 100, -500 + Math.random() * 100, 1); //in the statue base spawn.randomSmallMob(400 + Math.random() * 300, -150 + Math.random() * 100, 0.2); spawn.randomSmallMob(-1100 + Math.random() * 300, -150 + Math.random() * 100, 0.2); //bottom left spawn.randomMob(-2600 + Math.random() * 300, -700 + Math.random() * 300, 0.6); spawn.randomSmallMob(-3000 + Math.random() * 300, -400 + Math.random() * 300, 0.2); spawn.randomSmallMob(-3000 + Math.random() * 300, -400 + Math.random() * 300, 0); spawn.randomMob(-3900 + Math.random() * 100, -200 + Math.random() * 100, 0.6); spawn.randomMob(-3400 + Math.random() * 100, -400, 0.4); spawn.randomSmallMob(-3800 + Math.random() * 100, -700, -0.4); spawn.randomMob(-3400 + Math.random() * 100, -1000, 0.6); spawn.randomMob(-3000 + Math.random() * 100, -1850, 0); spawn.randomGroup(-2700, -2000, 0.4); //top left spawn.randomSmallMob(-3800, -5800, -0.2); spawn.randomSmallMob(-2400, -5200, 0.2); //top right spawn.randomGroup(2000, -5700, 0.6); powerUps.addResearchToLevel() //needs to run after mobs are spawned let bosses = ["shooterBoss", "launcherBoss", "laserTargetingBoss", "streamBoss", "pulsarBoss", "spawnerBossCulture", "laserBoss", "growBossCulture"]; let abc = Math.random(); if (simulation.difficulty > 3) { if (abc < 0.6) { spawn.randomLevelBoss(-1500 + Math.random() * 250, -1100 + Math.random() * 200, bosses); } else if (abc < 0.85) { spawn.laserBoss(-350 + Math.random() * 300, -600 + Math.random() * 200); } else { spawn.randomLevelBoss(850 + Math.random() * 250, -1100 + Math.random() * 200, bosses); } } spawn.secondaryBossChance(850 + Math.random() * 250, -1100 + Math.random() * 200) //draw leg for statue function statueLeg(shift, color) { ctx.save(); ctx.translate(shift, shift); //front leg let stroke = color; ctx.beginPath(); ctx.moveTo((s.h.x + shift) * s.scale, (s.h.y + shift) * s.scale); ctx.lineTo((s.k.x + 2 * shift) * s.scale, (s.k.y + shift) * s.scale); ctx.lineTo((s.f.x + shift) * s.scale, (s.f.y + shift) * s.scale); ctx.strokeStyle = stroke; ctx.lineWidth = 7 * s.scale; ctx.stroke(); //toe lines ctx.beginPath(); ctx.moveTo((s.f.x + shift) * s.scale, (s.f.y + shift) * s.scale); ctx.lineTo((s.f.x - 15 + shift) * s.scale, (s.f.y + 5 + shift) * s.scale); ctx.moveTo((s.f.x + shift) * s.scale, (s.f.y + shift) * s.scale); ctx.lineTo((s.f.x + 15 + shift) * s.scale, (s.f.y + 5 + shift) * s.scale); ctx.lineWidth = 4 * s.scale; ctx.stroke(); //hip joint ctx.beginPath(); ctx.arc((s.h.x + shift) * s.scale, (s.h.y + shift) * s.scale, 11 * s.scale, 0, 2 * Math.PI); //knee joint ctx.moveTo((s.k.x + 7 + 2 * shift) * s.scale, (s.k.y + shift) * s.scale); ctx.arc((s.k.x + 2 * shift) * s.scale, (s.k.y + shift) * s.scale, 7 * s.scale, 0, 2 * Math.PI); //foot joint ctx.moveTo((s.f.x + 6 + shift) * s.scale, (s.f.y + shift) * s.scale); ctx.arc((s.f.x + shift) * s.scale, (s.f.y + shift) * s.scale, 6 * s.scale, 0, 2 * Math.PI); ctx.fillStyle = s.fillColor; ctx.fill(); ctx.lineWidth = 2 * s.scale; ctx.stroke(); ctx.restore(); } // | | | | | // n - g o n //when s = 1 (scale), it's 3408 long and 800 tall (height of g) function hangingNGON(x, y, s, height, stiffness, pin, properties) { //makes a compound part of 3 bodyVertex parts function compound3Parts(x1, y1, v1, x2, y2, v2, x3, y3, v3, properties) { const part1 = Matter.Bodies.fromVertices(x1, y1, Vertices.fromPath(v1), properties); const part2 = Matter.Bodies.fromVertices(x2, y2, Vertices.fromPath(v2), properties); const part3 = Matter.Bodies.fromVertices(x3, y3, Vertices.fromPath(v3), properties); const compoundParts = Body.create({ parts: [part1, part2, part3], }); Composite.add(engine.world, [compoundParts]); needGravity[needGravity.length] = compoundParts; composite[composite.length] = compoundParts; body[body.length] = part1; body[body.length] = part2; body[body.length] = part3; setTimeout(function() { compoundParts.collisionFilter.category = cat.body; compoundParts.collisionFilter.mask = cat.body | cat.player | cat.bullet | cat.mob | cat.mobBullet | cat.map }, 1000); } //for attaching the block to a point function addConstraint(x, y, px, py, stiff, body, pin = false) { if (pin) { map[map.length] = Bodies.polygon(x, y, 0, 15); //circle above } cons[cons.length] = Constraint.create({ pointA: { x: x, y: y }, bodyB: body, pointB: { x: px, y: py }, stiffness: stiff }); Composite.add(engine.world, cons[cons.length - 1]); } //I SINCERELY APOLOGIZE FOR THE ILLEGIBLE BLOCKS OF STRING CONCATENATION //s is scale //n compound3Parts( x + 100 * s, y + 310 * s, ("0 0 " + 200 * s + " 0 " + 200 * s + " " + 620 * s + " 0 " + 620 * s), x + 300 * s, y + 160 * s, (200 * s + " " + 40 * s + " " + 400 * s + " " + 40 * s + " " + 400 * s + " " + 280 * s + " " + 200 * s + " " + 280 * s), x + 499 * s, y + 333.3 * s, (400 * s + " " + 40 * s + " " + 540 * s + " " + 40 * s + " " + 600 * s + " " + 100 * s + " " + 600 * s + " " + 620 * s + " " + 400 * s + " " + 620 * s + " " + 400 * s + " " + 280 * s), properties ); addConstraint(x + 300 * s, y - height, 0, -10 * s, stiffness, composite[composite.length - 1], pin); //- spawn.bodyRect(x + 800 * s, y + 250 * s, 200 * s, 100 * s, 1, properties); body[body.length - 1].frictionAir = 0.05 //friction to make jump easier addConstraint(x + 900 * s, y - height, 0, -30 * s, stiffness, body[body.length - 1], pin); //g compound3Parts( x + 1400 * s, y + 300 * s, ("0 0 " + 250 * s + " 0 " + 425 * s + " " + 175 * s + " " + 425 * s + " " + 450 * s + " " + 275 * s + " " + 600 * s + " 0 " + 600 * s + " " + -175 * s + " " + 425 * s + " " + -175 * s + " " + 175 * s), x + 1636 * s, y + 633 * s, (425 * s + " " + 450 * s + " " + 425 * s + " " + 750 * s + " " + 375 * s + " " + 800 * s + " " + 275 * s + " " + 675 * s + " " + 275 * s + " " + 600 * s), x + 1398 * s, y + 737 * s, (375 * s + " " + 800 * s + " " + -75 * s + " " + 800 * s + " " + -75 * s + " " + 675 * s + " " + 275 * s + " " + 675 * s), properties ); addConstraint(x + 1500 * s, y - height, 0, -15 * s, stiffness, composite[composite.length - 1], pin); //o spawn.bodyVertex( x + 2300 * s, y + 300 * s, ("0 0 " + 250 * s + " 0 " + 425 * s + " " + 175 * s + " " + 425 * s + " " + 425 * s + " " + 250 * s + " " + 600 * s + " 0 " + 600 * s + " " + -175 * s + " " + 425 * s + " " + -175 * s + " " + 175 * s), properties ); addConstraint(x + 2300 * s, y - height, 0, -10 * s, stiffness, body[body.length - 1], pin); //n compound3Parts( x + 2900 * s, y + 310 * s, ("0 0 " + 200 * s + " 0 " + 200 * s + " " + 620 * s + " 0 " + 620 * s), x + 3100 * s, y + 160 * s, (200 * s + " " + 40 * s + " " + 400 * s + " " + 40 * s + " " + 400 * s + " " + 280 * s + " " + 200 * s + " " + 280 * s), x + 3300 * s, y + 333.3 * s, (400 * s + " " + 40 * s + " " + 540 * s + " " + 40 * s + " " + 600 * s + " " + 100 * s + " " + 600 * s + " " + 620 * s + " " + 400 * s + " " + 620 * s + " " + 400 * s + " " + 280 * s), properties ); addConstraint(x + 3100 * s, y - height, 0, -10 * s, stiffness, composite[composite.length - 1], pin); } }, tunnel() { // by Scarlettt level.custom = () => { level.exit.drawAndCheck(); //enter 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 = "#013"; ctx.fill(); //exit 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 = "#9ff"; ctx.fill(); // hiding rooms in path to second floor ctx.fillStyle = "#322"; ctx.fillRect(3750, -1650, 3500, 350); // prevent the user from getting into the secreter room without defeating all mobs if (m.pos.x > 1500 && m.pos.x < 2500 && m.pos.y > -4000 && m.pos.y < -3500 && mob.reduce((a, i) => { return a || ((Math.sqrt((i.position.x - 3600) * (i.position.x - 3600) + (i.position.y + 3600) * (i.position.y + 3600)) < 20000) && i.isDropPowerUp); }, false) && !emergencyActivated) { Matter.Body.setPosition(player, { x: 2800, y: m.pos.y }); } button.query(); isButtonTapped = isButtonTapped || !button.isUp; hazard.level(!isButtonTapped); if (Matter.Query.region([player], hazard).length) m.energy -= 0.001; buttonSec.query(); buttonSec.draw(); if (!buttonSec.isUp && !hasSecretButton) { for (var i = 0; i < 5; i++) { powerUps.spawn(3614, -3700, "ammo"); } hasSecretButton = true; } buttonThird.query(); buttonThird.draw(); if (!buttonThird.isUp && !hasSecretButton2) { for (var i = 0; i < 4; i++) powerUps.spawn(1614, -3700, "research"); hasSecretButton2 = true; } if (!buttonSec.isUp) { secretAnimTrans += 2; secretAnimTime = 1; secretAnimTrans = Math.max(0, Math.min(secretAnimTrans, 60)); } else { secretAnimTrans--; if (secretAnimTime) secretAnimTrans += 3; secretAnimTrans = Math.min(60, Math.max(secretAnimTrans, 0)); } if (secretAnimTime > 0) { secretAnimTime++; if (secretAnimTime > 150) secretAnimTime = 0; } if (emergencyActivated || !buttonThird.isUp) { secretAnimTrans2 += 2; secretAnimTime2 = 1; secretAnimTrans2 = Math.max(0, Math.min(secretAnimTrans2, 60)); } else { secretAnimTrans2--; if (secretAnimTime2) secretAnimTrans2 += 3; secretAnimTrans2 = Math.min(60, Math.max(secretAnimTrans2, 0)); } if (secretAnimTime2 > 0) { secretAnimTime2++; if (secretAnimTime2 > 150) secretAnimTime2 = 0; } ctx.beginPath(); ctx.arc(m.pos.x, m.pos.y, 200, 0, 2 * Math.PI); ctx.fillStyle = "#ff25"; ctx.fill(); ctx.beginPath(); ctx.arc(m.pos.x, m.pos.y, 400, 0, 2 * Math.PI); ctx.fillStyle = "#ff22"; ctx.fill(); ctx.beginPath(); ctx.arc(m.pos.x, m.pos.y, 700, 0, 2 * Math.PI); ctx.fillStyle = "#ff21"; ctx.fill(); elevator.move(); elevator.drawTrack(); }; level.customTopLayer = () => { hazard.query(); secretHazard.level(emergencyActivated); secretHazard.query(); button.draw(); // Fire damage let isInRange = flames.reduce((a, i) => a || Math.sqrt((m.pos.x - i[0]) * (m.pos.x - i[0]) + (m.pos.y + 90 - i[1]) * (m.pos.y + 90 - i[1])) < 50, false); if (isInRange) { fireDmgLevel++; fireDmgLevel = Math.min(fireDmgLevel, 100); } else { fireDmgLevel--; fireDmgLevel = Math.max(fireDmgLevel, -8); } if (fireDmgLevel > -8) { ctx.fillStyle = "#fa0b"; ctx.fillRect(m.pos.x - 50, m.pos.y - 100, Math.min(fireDmgLevel * 12.5 + 100, 100), 15); } if (fireDmgLevel > 0) { ctx.fillStyle = "#f00c"; ctx.fillRect(m.pos.x - 50, m.pos.y - 100, fireDmgLevel, 15); m.damage(0.001 * (1.5 * isInRange + 1)); drawFlame(m.pos.x, m.pos.y + 90, "#d40", Math.PI / 2 + 1); drawFlame(m.pos.x, m.pos.y + 90, "#d40", Math.PI / 2 + 1); drawFlame(m.pos.x, m.pos.y + 90, "#d40", Math.PI / 2 + 1); drawFlame(m.pos.x, m.pos.y + 90, "#d40", Math.PI / 2 - 1); drawFlame(m.pos.x, m.pos.y + 90, "#d40", Math.PI / 2 - 1); drawFlame(m.pos.x, m.pos.y + 90, "#d40", Math.PI / 2 - 1); drawFlame(m.pos.x, m.pos.y + 90, "#f70", Math.PI / 2); drawFlame(m.pos.x, m.pos.y + 90, "#f70", Math.PI / 2); drawFlame(m.pos.x, m.pos.y + 90, "#f70", Math.PI / 2); } for (let j = 0; j < 5; j++) { drawFlame(1130 + j * 10, -1700) for (let i = 0; i < 7; i++) drawFlame(2550 + i * 200, -2800); for (let i = 0; i < 10; i++) drawFlame(2800 + i * 500, -1650); for (let i = 0; i < 9; i++) drawFlame(1595 + i * 95, -3860); drawFlame(4850, -1300); drawFlame(6350, -1300); } ctx.fillStyle = "#541"; for (let i = 0; i < 9; i++) { ctx.fillRect(1592 + i * 95, -3860, 6, 70); } if (m.pos.x > 1500 && m.pos.x < 3750 && m.pos.y > -5000 && m.pos.y < -3300) { secretRoomTrans -= 5; secretRoomTrans = Math.max(secretRoomTrans, 85); } else { secretRoomTrans += 5; secretRoomTrans = Math.min(secretRoomTrans, 250); } let hasMob = mob.reduce((a, i) => { return a || ((Math.sqrt((i.position.x - 3600) * (i.position.x - 3600) + (i.position.y + 3600) * (i.position.y + 3600)) < 20000) && i.isDropPowerUp); }, false) && !emergencyActivated; door.isClosing = hasMob; door.openClose(); ctx.fillStyle = "#444444" + secretRoomTrans.toString(16); ctx.fillRect(1480, -5000, 2270, 1710); if (hasMob) { ctx.fillStyle = "#444"; ctx.fillRect(1480, -5000, 1070, 1710); } if (secretAnimTrans > 0) { drawProject([3614, -3530], [2900, -3900], [3400, -3600], secretAnimTrans, 60); if (secretAnimTrans >= 42) { ctx.font = "27px monospace"; ctx.textAlign = "start" ctx.fillStyle = "#00ffff" + Math.floor((secretAnimTrans - 40) * 12.75).toString(16); ctx.fillText("Waste Discharge Interruption:", 2910, -3870); ctx.fillText("Owner 'Scarlet' not found", 2910, -3830); ctx.fillText("Detected user: 'm'", 2910, -3790); ctx.fillStyle = (hasMob ? "#ff6644" : "#ffff44") + Math.floor((secretAnimTrans - 40) * 12.75).toString(16); ctx.fillText(hasMob ? "AREA HAS MOBS." : "Area clear.", 2910, -3710); ctx.fillText(hasMob ? "'openDoor' failed." : "'openDoor' complete.", 2910, -3670); ctx.strokeStyle = "#00ff00" + Math.floor((secretAnimTrans - 40) * 6).toString(16); ctx.beginPath(); ctx.arc(3300, -3730, 60, 0, 2 * Math.PI); ctx.stroke(); ctx.arc(3330, -3730, 8, 0, 2 * Math.PI); ctx.lineWidth = 4; ctx.stroke(); ctx.textAlign = "center"; ctx.fillStyle = "#00ffff" + Math.floor((secretAnimTrans - 40) * 12.75).toString(16); ctx.font = "30px monospace"; ctx.fillText("n-gon inc", 3300, -3630); ctx.font = "25px Arial"; } } if (secretAnimTrans2 > 0) { drawProject([1614, -3530], [2050, -3900], [1550, -3600], secretAnimTrans2, 60); if (secretAnimTrans2 >= 42) { ctx.font = "27px monospace"; ctx.textAlign = "start"; ctx.fillStyle = "#00ffff" + Math.floor((secretAnimTrans2 - 40) * 12.75).toString(16); ctx.fillText("SECURITY BREACH DETECTED", 1560, -3870); ctx.fillText("Entity name: m", 1560, -3830); ctx.fillStyle = (tech.totalCount < 25 ? (tech.totalCount < 10 ? "#ffff44" : "#22ff22") : "#ff6644") + Math.floor((secretAnimTrans2 - 40) * 12.75).toString(16); ctx.fillText("Threat level: " + (tech.totalCount < 25 ? (tech.totalCount < 10 ? "Low" : "Medium") : "HIGH"), 1560, -3790); if (tech.totalCount >= 15) ctx.fillText("PROCEDURE ACTIVATED", 1560, -3750); ctx.strokeStyle = "#00ff00" + Math.floor((secretAnimTrans2 - 40) * 6).toString(16); ctx.beginPath(); ctx.arc(1950, -3730, 60, 0, 2 * Math.PI); ctx.stroke(); ctx.arc(1980, -3730, 8, 0, 2 * Math.PI); ctx.lineWidth = 4; ctx.stroke(); ctx.textAlign = "center"; ctx.fillStyle = "#00ffff" + Math.floor((secretAnimTrans2 - 40) * 12.75).toString(16); ctx.font = "30px monospace"; ctx.fillText("n-gon inc", 1950, -3630); ctx.font = "25px Arial"; if (secretAnimTrans2 >= 60) { if (!emergencyActivated && tech.totalCount >= 10) { for (let i = 0; i < 5; i++) { spawn.exploder(1614, -3900); if (tech.totalCount >= 25) spawn.randomMob(1614, -3900, Infinity); } emergencyActivated = true; } } } } }; level.setPosToSpawn(0, -50); //normal spawn level.exit.x = 8500; level.exit.y = 680; level.defaultZoom = 1800 simulation.zoomTransition(level.defaultZoom) document.body.style.backgroundColor = "#123"; // powerUps.spawnStartingPowerUps(1475, -1175); // spawn.debris(750, -2200, 3700, 16); //16 debris per level // spawn blocks spawn.mapRect(-100, 0, 1050, 100); spawn.mapRect(900, -300, 50, 300); spawn.mapRect(700, -300, 50, 200); // first room spawn.mapRect(-100, -350, 850, 50); spawn.mapRect(900, -350, 850, 50); spawn.mapRect(-100, -1550, 50, 1200); spawn.mapRect(1700, -1550, 50, 1200); spawn.mapRect(-100, -1550, 850, 50); spawn.mapRect(900, -1550, 850, 50); spawn.bodyRect(700, -400, 50, 50); spawn.bodyRect(900, -400, 50, 50); spawn.mapRect(500, -650, 650, 25); spawn.mapRect(200, -1000, 200, 25); spawn.mapRect(1250, -1000, 200, 25); spawn.mapRect(600, -1300, 450, 25); spawn.mapRect(700, -1650, 50, 100); spawn.mapRect(900, -1650, 50, 100); // pathway to second room spawn.mapRect(950, -1650, 3050, 50); spawn.mapRect(1100, -1700, 100, 50); // second room spawn.mapRect(0, -5000, 1500, 3000); spawn.mapRect(1500, -2050, 300, 50); spawn.mapRect(2000, -3100, 300, 1100); spawn.mapRect(1500, -5000, 2250, 1000); spawn.mapRect(1500, -3500, 1050, 225); spawn.mapRect(4000, -5000, 500, 3000); spawn.mapRect(3748, -5000, 252, 1550); spawn.mapRect(1700, -2400, 300, 50); spawn.mapRect(1500, -2750, 300, 50); spawn.mapRect(2300, -3000, 1700, 50); spawn.mapRect(2300, -2800, 1700, 800); spawn.mapRect(2450, -3300, 1300, 100); // secret room in second room spawn.mapRect(2700, -3500, 1050, 50); spawn.mapRect(2549, -5000, 1201, 1000); const buttonSec = level.button(3550, -3500); const buttonThird = level.button(1550, -3500); let hasSecretButton = false, hasSecretButton2 = false, secretAnimTrans = 0, secretAnimTime = 0, secretAnimTrans2 = 0, secretAnimTime2 = 0; let emergencyActivated = false; const door = level.door(2450, -4000, 100, 500, 490); const secretHazard = level.hazard(1500, -4000, 1000, 510, 0.01); // hazards const button = level.button(3800, -3000); const hazard = level.hazard(2300, -3090, 1700, 110, 0.005); let isButtonTapped = false; // if (b.inventory.length < 5) powerUps.spawn(3800, -3200, "gun"); powerUps.spawn(3900, -3100, "heal", true, null, 30); powerUps.spawn(3900, -3100, "heal", true, null, 30); // path to the third room spawn.mapRect(2000, -1850, 50, 200); spawn.mapRect(2200, -2000, 50, 200); spawn.mapRect(2400, -1850, 50, 200); spawn.mapRect(4200, -1650, 1300, 50); spawn.mapRect(5700, -1650, 1300, 50); spawn.mapRect(7200, -1650, 750, 50); spawn.mapRect(3700, -1600, 50, 350); spawn.mapRect(7250, -1600, 50, 350); spawn.mapRect(3750, -1300, 3500, 50); spawn.mapRect(4500, -2150, 3550, 50) // third room spawn.mapRect(7900, -1600, 50, 1000); spawn.mapRect(8050, -3000, 50, 2400); spawn.mapRect(7000, -600, 950, 50); spawn.mapRect(8050, -600, 950, 50); spawn.mapRect(7000, -600, 50, 1000); spawn.mapRect(8950, -600, 50, 1000); spawn.mapRect(7000, 400, 950, 50); spawn.mapRect(8050, 400, 950, 50); spawn.mapRect(7900, 400, 50, 300); spawn.mapRect(7900, 700, 1000, 50); const elevator = level.elevator(7962.5, 500, 75, 50, -1800) // fire damage const flames = []; flames.push([1150, -1700], [1150, -1770]); for (let i = 0; i < 10; i++) flames.push([2800 + i * 500, -1650], [2800 + i * 500, -1720]); flames.push([4850, -1300], [6350, -1300], [4850, -1370], [6350, -1370]); let fireDmgLevel = -8; let secretRoomTrans = 250; // mobs let mobList1 = [ [500, -750], [1150, -750], [825, -1100], [300, -1100], [1350, -1100] ]; while (mobList1.length > 5 - Math.sqrt(simulation.difficulty * 2.5) && mobList1.length) { let rand = Math.floor(Math.random() * mobList1.length); spawn[["hopper", "sneaker", "striker"][Math.floor(Math.random() * 3)]](mobList1[rand][0], mobList1[rand][1], 60 + Math.random() * 10); mobList1.splice(rand, 1); } let hasLaser = spawn.pickList.includes("laser"); if (hasLaser) spawn.pickList.splice(spawn.pickList.indexOf("laser"), 1); let mobList2 = [ [50, -1400], [1600, -450], [50, -450], [1600, -1400] ]; for (let i = 0; i < 10; i++) mobList2.push([2800 + i * 500, -1800]); while (mobList2.length && mob.length < -1 + 16 * Math.log10(simulation.difficulty + 1)) { let rand = Math.floor(Math.random() * mobList2.length); spawn.randomMob(...mobList2[rand]); mobList2.splice(rand, 1); } let groupList = ["spawn.randomGroup(8250, 575);", `spawn.randomGroup(3200, -3700); if (simulation.difficulty > 15) spawn.randomGroup(3500, -3700, 0.3);`, "spawn.randomGroup(7800, -1800, 0.5);" ]; while (groupList.length > 0) { let ind = Math.floor(Math.random() * groupList.length); Function(groupList[ind])(); groupList.splice(ind, 1); } if (hasLaser) spawn.pickList.push("laser"); spawn.shieldingBoss(3900, -3200, 70); let randomBoss = Math.floor(Math.random() * 2); if (simulation.difficulty > 5) spawn[["shooterBoss", "launcherBoss"][randomBoss]](7500, -150, 100, false); else spawn[["shooter", "launcher"][randomBoss]](7500, -150, 150); spawn[["shooter", "launcher"][randomBoss]](8500, -150, 150); // canvas stuff function drawFlame(x, y, color = "#f81", angle = Math.PI / 2) { ctx.beginPath(); ctx.moveTo(x, y); ctx.strokeStyle = color; ctx.lineWidth = 3; for (let i = 0; i < 3; i++) { let randAng = (Math.random() - 0.5) * 2 + angle; randLen = 30 + Math.random() * 10; x = x + Math.cos(randAng) * randLen; y = y - Math.sin(randAng) * randLen; ctx.lineTo(x, y); } ctx.stroke(); } function drawProject(startPos, endPos1, endPos2, tValue, tValueM) { ctx.strokeStyle = "#003"; ctx.fillStyle = "#0055aa" + ('0' + (tValue * 60 / tValueM).toString(16)).slice(-2); let inter = (tValueM - tValue) / tValueM; let endpos1i = endPos1.map((i, j) => (startPos[j] - i) * inter), endpos2i = endPos2.map((i, j) => (startPos[j] - i) * inter); ctx.beginPath(); ctx.moveTo(endPos1[0] + endpos1i[0], endPos1[1] + endpos1i[1]); ctx.lineTo(...startPos); ctx.lineTo(endPos2[0] + endpos2i[0], endPos1[1] + endpos1i[1]); ctx.fill(); ctx.stroke(); ctx.beginPath(); ctx.moveTo(endPos1[0] + endpos1i[0], endPos1[1] + endpos1i[1]); ctx.lineTo(...startPos); ctx.lineTo(endPos1[0] + endpos1i[0], endPos2[1] + endpos2i[1]); ctx.fill(); ctx.stroke(); ctx.beginPath(); ctx.moveTo(endPos1[0] + endpos1i[0], endPos2[1] + endpos2i[1]); ctx.lineTo(...startPos); ctx.lineTo(endPos2[0] + endpos2i[0], endPos2[1] + endpos2i[1]); ctx.fill(); ctx.stroke(); ctx.beginPath(); ctx.moveTo(endPos2[0] + endpos2i[0], endPos2[1] + endpos2i[1]); ctx.lineTo(...startPos); ctx.lineTo(endPos2[0] + endpos2i[0], endPos1[1] + endpos1i[1]); ctx.fill(); ctx.stroke(); if (tValue >= tValueM * 2 / 3) { ctx.fillStyle = "#0055aa" + ('0' + Math.floor((tValue - tValueM * 2 / 3) * 6.25 * 60 / tValueM).toString(16)).slice(-2); ctx.strokeStyle = "#000033" + ('0' + Math.floor((tValue - tValueM * 2 / 3) * 12.75 * 60 / tValueM).toString(16)).slice(-2); ctx.fillRect(endPos1[0], endPos1[1], endPos2[0] - endPos1[0], endPos2[1] - endPos1[1]); ctx.shadowColor = "#00aaaa" + ('0' + Math.floor((tValue - tValueM * 2 / 3) * 12.75 * 60 / tValueM).toString(16)).slice(-2); ctx.shadowBlur = 10; ctx.strokeRect(endPos1[0], endPos1[1], endPos2[0] - endPos1[0], endPos2[1] - endPos1[1]); ctx.shadowBlur = 0; ctx.shadowColor = "#0000"; } } }, run() { addPartToMap = (len) => { //adds new map elements to the level while the level is already running //don't forget to run simulation.draw.setPaths() after you all the the elements so they show up visually map[len].collisionFilter.category = cat.map; map[len].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet; Matter.Body.setStatic(map[len], true); //make static Composite.add(engine.world, map[len]); } anotherBoss = (x, y) => { if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) { tech.isScaleMobsWithDuplication = true spawn.randomLevelBoss(x, y, ["historyBoss"]); tech.isScaleMobsWithDuplication = false } else if (tech.isResearchBoss) { if (powerUps.research.count > 3) { powerUps.research.changeRerolls(-4) simulation.makeTextLog(`m.research -= 4
${powerUps.research.count}`) } else { tech.addJunkTechToPool(0.49) } // spawn.randomLevelBoss(x, y, ["historyBoss"]); } } const climbPad = level.boost(8200, -200, 500); var climbTime = false; var climbGroup = 0; var initialSpawn = false; var endTime = false; let runMobList = [ "hopper", "slasher", "striker", "stabber", "springer", "pulsar", "sneaker", "spinner", "grower", "focuser", "spawner", ]; let removeList = []; level.custom = () => { level.exit.drawAndCheck(); level.enter.draw(); climbPad.query(); if (m.pos.x > 8000 && climbTime === false) { spawn.mapRect(7800, -900, 200, 900); addPartToMap(map.length - 1); simulation.draw.setPaths(); simulation.makeTextLog(`UNKNOWN: "Well done. Now climb."`, 600); simulation.makeTextLog(`UNKNOWN: "I left a gift at the top."`, 600); climbTime = true; } //toggles on a mapRect when player passes a certain area if (m.pos.x > 9000 && endTime === false) { simulation.makeTextLog("UNKNOWN: \"Good luck. I hope you get out of here.\"", 600); endTime = true; } for (i in mob) { mob[i].damageReduction = 0; Matter.Body.setVelocity(mob[i], { x: mob[i].velocity.x * 0.97, y: mob[i].velocity.y * 0.97 }); } //makes everything slow and immune }; level.customTopLayer = () => { ctx.fillStyle = "#888"; if (climbGroup === 0) { //toggle on fillRect: 1 ctx.fillRect(8000, -900, 300, 100); ctx.fillRect(8500, -1800, 300, 100); ctx.fillRect(8300, -2700, 300, 100); ctx.fillRect(8000, -3600, 300, 100); ctx.fillRect(8200, -4500, 300, 100); } else if (climbGroup === 1) { //toggle on fillRect: 2 ctx.fillRect(8300, -1200, 300, 100); ctx.fillRect(8500, -2100, 300, 100); ctx.fillRect(8100, -3000, 300, 100); ctx.fillRect(8000, -3900, 300, 100); ctx.fillRect(8200, -4800, 300, 100); } else if (climbGroup === 2) { //toggle on fillRect: 0 ctx.fillRect(8500, -600, 300, 100); ctx.fillRect(8100, -1500, 300, 100); ctx.fillRect(8000, -2400, 300, 100); ctx.fillRect(8500, -3300, 300, 100); ctx.fillRect(8500, -4200, 300, 100); } if ((simulation.cycle % 120) === 0) { for (var i = 0; i < map.length; i++) { if (map[i].isRemove) { Matter.Composite.remove(engine.world, map[i]); map.splice(i, 1); } } if (climbGroup === 0) { //toggle on platforms: 0 spawn.mapRect(8000, -900, 300, 100); addPartToMap(map.length - 1); map[map.length - 1].isRemove = true; spawn.mapRect(8500, -1800, 300, 100); addPartToMap(map.length - 1); map[map.length - 1].isRemove = true; spawn.mapRect(8300, -2700, 300, 100); addPartToMap(map.length - 1); map[map.length - 1].isRemove = true; spawn.mapRect(8000, -3600, 300, 100); addPartToMap(map.length - 1); map[map.length - 1].isRemove = true; spawn.mapRect(8200, -4500, 300, 100); addPartToMap(map.length - 1); map[map.length - 1].isRemove = true; climbGroup = 1; } else if (climbGroup === 1) { //toggle on platforms: 1 spawn.mapRect(8300, -1200, 300, 100); addPartToMap(map.length - 1); map[map.length - 1].isRemove = true; spawn.mapRect(8500, -2100, 300, 100); addPartToMap(map.length - 1); map[map.length - 1].isRemove = true; spawn.mapRect(8100, -3000, 300, 100); addPartToMap(map.length - 1); map[map.length - 1].isRemove = true; spawn.mapRect(8000, -3900, 300, 100); addPartToMap(map.length - 1); map[map.length - 1].isRemove = true; spawn.mapRect(8200, -4800, 300, 100); addPartToMap(map.length - 1); map[map.length - 1].isRemove = true; climbGroup = 2; } else if (climbGroup === 2) { //toggle on platforms: 2 spawn.mapRect(8500, -600, 300, 100); addPartToMap(map.length - 1); map[map.length - 1].isRemove = true; spawn.mapRect(8100, -1500, 300, 100); addPartToMap(map.length - 1); map[map.length - 1].isRemove = true; spawn.mapRect(8000, -2400, 300, 100); addPartToMap(map.length - 1); map[map.length - 1].isRemove = true; spawn.mapRect(8500, -3300, 300, 100); addPartToMap(map.length - 1); map[map.length - 1].isRemove = true; spawn.mapRect(8500, -4200, 300, 100); addPartToMap(map.length - 1); map[map.length - 1].isRemove = true; climbGroup = 0; } simulation.draw.setPaths(); //update map graphics } //every 120 cycles, first deletes previous group, then cycles through one of 3 toggle groups }; if (!initialSpawn) { level.defaultZoom = 1300 //was 800 I changed this simulation.zoomTransition(level.defaultZoom) document.body.style.backgroundColor = "#dcdcde"; //Level level.setPosToSpawn(-100, -1450); spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); level.exit.x = 9300; level.exit.y = -5130; spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20); //Map spawn.mapRect(-1400, -2200, 1700, 200); spawn.mapRect(100, -2200, 200, 1000); spawn.mapRect(-600, -1400, 8600, 200); spawn.mapRect(-1400, -2200, 200, 1000); spawn.mapRect(-2800, -1400, 1600, 200); spawn.mapRect(-2800, -1400, 200, 1400); spawn.mapRect(-2800, -200, 11800, 200); spawn.mapRect(-900, -600, 600, 600); spawn.mapRect(200, -800, 500, 100); spawn.mapRect(1300, -1400, 200, 900); spawn.mapRect(1300, -600, 500, 100); spawn.mapRect(2300, -800, 200, 200); spawn.mapRect(2900, -400, 100, 400); spawn.mapRect(3200, -600, 100, 600); spawn.mapRect(3500, -800, 100, 800); spawn.mapRect(4400, -900, 500, 100); spawn.mapRect(4400, -600, 500, 100); spawn.mapRect(4800, -900, 100, 400); spawn.mapRect(5300, -550, 600, 550); spawn.mapRect(5600, -900, 300, 800); spawn.mapRect(6300, -300, 1100, 300); spawn.mapRect(6600, -400, 500, 200); spawn.mapRect(6600, -800, 500, 100); spawn.mapRect(7000, -1400, 100, 700); spawn.mapRect(7800, -5900, 200, 5100); spawn.mapRect(7800, -5900, 1900, 200); spawn.mapRect(9500, -5900, 200, 1000); spawn.mapRect(8800, -5100, 900, 200); spawn.mapRect(8800, -5100, 200, 5100); //Text spawn.mapRect(400, -1600, 100, 10); spawn.mapRect(400, -1600, 10, 100); spawn.mapRect(490, -1600, 10, 40); spawn.mapRect(400, -1570, 100, 10); spawn.mapRect(400, -1540, 100, 10); spawn.mapRect(490, -1540, 10, 40); spawn.mapRect(600, -1600, 10, 100); spawn.mapRect(600, -1510, 100, 10); spawn.mapRect(690, -1600, 10, 100); spawn.mapRect(800, -1600, 100, 10); spawn.mapRect(800, -1600, 10, 100); spawn.mapRect(890, -1600, 10, 100); spawn.mapRect(0, 0, 1, 1); //dont ask why i have these spawn.mapRect(1, 0, 1, 1); //dont ask why i have these spawn.mapRect(0, 1, 1, 1); //dont ask why i have these spawn.mapRect(1, 1, 1, 1); //dont ask why i have these spawn.mapRect(-1, 0, 1, 1); //dont ask why i have these spawn.mapRect(0, -1, 1, 1); //dont ask why i have these spawn.mapRect(-1, -1, 1, 1); //dont ask why i have these spawn.mapRect(1, -1, 1, 1); //dont ask why i have these spawn.mapRect(-1, 1, 1, 1); //dont ask why i have these //Mob Spawning setTimeout(() => { simulation.makeTextLog("UNKNOWN: \"You cannot kill them.\"", 600); }, 2000); setTimeout(() => { simulation.makeTextLog("UNKNOWN: \"But I have slowed them down for you.\"", 600); }, 6000); spawn[runMobList[Math.floor(Math.random() * runMobList.length)]](200, -400); spawn[runMobList[Math.floor(Math.random() * runMobList.length)]](1800, -1000); spawn[runMobList[Math.floor(Math.random() * runMobList.length)]](3200, -1000); spawn[runMobList[Math.floor(Math.random() * runMobList.length)]](6200, -400); if (simulation.difficulty > 10) { spawn[runMobList[Math.floor(Math.random() * runMobList.length)]](1000, -400); spawn[runMobList[Math.floor(Math.random() * runMobList.length)]](2400, -400); spawn[runMobList[Math.floor(Math.random() * runMobList.length)]](4000, -400); spawn[runMobList[Math.floor(Math.random() * runMobList.length)]](6600, -1000); setTimeout(() => { simulation.makeTextLog("UNKNOWN: \"Run.\"", 600); }, 10000); } //some of the mobs if (simulation.difficulty > 20) { spawn[runMobList[Math.floor(Math.random() * runMobList.length)]](1000, -1000); spawn[runMobList[Math.floor(Math.random() * runMobList.length)]](3100, -300); spawn[runMobList[Math.floor(Math.random() * runMobList.length)]](4200, -1000); spawn[runMobList[Math.floor(Math.random() * runMobList.length)]](7400, -800); setTimeout(() => { simulation.makeTextLog("UNKNOWN: \"RUN!\"", 600); }, 11000); } //most of the mobs if (simulation.difficulty > 30) { spawn[runMobList[Math.floor(Math.random() * runMobList.length)]](200, -1000); spawn[runMobList[Math.floor(Math.random() * runMobList.length)]](3400, -300); spawn[runMobList[Math.floor(Math.random() * runMobList.length)]](5200, -800); spawn[runMobList[Math.floor(Math.random() * runMobList.length)]](7500, -300); setTimeout(() => { simulation.makeTextLog("UNKNOWN: \"GET OUT OF HERE.\"", 600); }, 12000); } //all the mobs //Boss Spawning if (simulation.difficulty > 5) { spawn.randomLevelBoss(-2200, -700, ["powerUpBossBaby", "blockBoss", "revolutionBoss"]); setTimeout(() => { simulation.makeTextLog("UNKNOWN: \"They are coming for you.\"", 600); }, 14000); } anotherBoss(-1800, -700); //custom second boss spawn //Blocks spawn.bodyRect(1300, -500, 200, 100); spawn.bodyRect(1400, -500, 200, 100); spawn.bodyRect(1500, -500, 200, 100); spawn.bodyRect(5700, -1200, 100, 100); spawn.bodyRect(5700, -1100, 100, 100); spawn.bodyRect(5700, -1000, 100, 100); spawn.bodyRect(6800, -700, 100, 100); spawn.bodyRect(6800, -600, 100, 100); spawn.bodyRect(6800, -500, 100, 100); spawn.debris(4400, -300, 500, 16); spawn.debris(3300, -600, 200, 6); spawn.debris(3000, -500, 20, 6); spawn.debris(2300, -300, 200, 6); spawn.debris(200, -300, 500, 16); //Powerups if (simulation.difficulty > 10) { powerUps.spawn(1600, -700, "tech"); } powerUps.spawnRandomPowerUp(1700, -700); // if (simulation.difficulty > 20) { // powerUps.spawn(4600, -700, "tech"); // } powerUps.spawnRandomPowerUp(4700, -700); // if (simulation.difficulty > 30) { // powerUps.spawn(6800, -1000, "tech"); // } powerUps.spawnRandomPowerUp(6900, -1000); powerUps.spawn(9200, -5400, "tech"); if (simulation.difficulty > 10) { powerUps.spawn(9200, -5500, "tech"); } // if (simulation.difficulty > 20) { // powerUps.spawn(9200, -5600, "tech"); // } // if (simulation.difficulty > 30) { // powerUps.spawn(9200, -5700, "tech"); // } powerUps.addResearchToLevel() //needs to run after mobs are spawned initialSpawn == true; } }, // ******************************************************************************************************** // ******************************************************************************************************** // ***************************************** training levels ********************************************** // ******************************************************************************************************** // ******************************************************************************************************** walk() { //learn to walk m.addHealth(Infinity) document.getElementById("health").style.display = "none" //hide your health bar document.getElementById("health-bg").style.display = "none" level.setPosToSpawn(60, -50); //normal spawn spawn.mapRect(10, -10, 100, 20); //small platform for player level.exit.x = 1775; level.exit.y = -35; spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump simulation.zoomScale = 1400 //1400 is normal level.defaultZoom = 1400 simulation.zoomTransition(level.defaultZoom, 1) document.body.style.backgroundColor = level.trainingBackgroundColor simulation.lastLogTime = 0; //clear previous messages let instruction = 0 level.trainingText(`move ↔ with ${input.key.left.replace('Key', '').replace('Digit', '')} and ${input.key.right.replace('Key', '').replace('Digit', '')}`) level.custom = () => { if (instruction === 0 && input.right) { instruction++ level.trainingText(`move ↔ with ${input.key.left.replace('Key', '').replace('Digit', '')} and ${input.key.right.replace('Key', '').replace('Digit', '')}
exit through the blue door`) } //exit room ctx.fillStyle = "#f2f2f2" ctx.fillRect(1600, -400, 400, 400) level.enter.draw(); level.exit.drawAndCheck(); }; level.customTopLayer = () => { //exit room glow ctx.fillStyle = "rgba(0,255,255,0.05)" ctx.fillRect(1600, -400, 400, 400) }; spawn.mapRect(-2750, -2800, 2600, 4600); //left wall spawn.mapRect(2000, -2800, 2600, 4600); //right wall spawn.mapRect(-250, 0, 3500, 1800); //floor spawn.mapRect(1575, 0, 500, 100); spawn.mapRect(-250, -2800, 3500, 2200); //roof spawn.mapRect(700, -8, 50, 25); spawn.mapRect(725, -16, 75, 25); spawn.mapRect(1375, -16, 50, 50); spawn.mapRect(1400, -8, 50, 25); spawn.mapRect(750, -24, 650, 100); spawn.mapRect(1600, -1200, 500, 850); //exit roof spawn.mapRect(1600, -400, 50, 225); //exit room left upper wall }, crouch() { //learn to crouch if (localSettings.isTrainingNotAttempted) { //after making it to the second training level localSettings.isTrainingNotAttempted = false // this makes the training button less obvious at the start screen if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage } m.addHealth(Infinity) level.setPosToSpawn(75, -100); //normal spawn spawn.mapRect(25, -60, 100, 20); //small platform for player spawn.mapRect(0, -50, 150, 25); //stairs spawn.mapRect(-25, -40, 200, 25); spawn.mapRect(-50, -30, 250, 25); spawn.mapRect(-75, -20, 300, 25); spawn.mapRect(-100, -10, 350, 25); spawn.mapRect(-150, -50, 175, 75); level.exit.x = 1775; level.exit.y = -35; spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump simulation.zoomScale = 1400 //1400 is normal level.defaultZoom = 1400 simulation.zoomTransition(level.defaultZoom, 1) document.body.style.backgroundColor = level.trainingBackgroundColor let instruction = 0 level.trainingText(`press ${input.key.down.replace('Key', '').replace('Digit', '')} to crouch`) level.custom = () => { if (instruction === 0 && input.down) { instruction++ level.trainingText(`press ${input.key.down.replace('Key', '').replace('Digit', '')} to crouch`) } //exit room ctx.fillStyle = "#f2f2f2" ctx.fillRect(1625, -350, 375, 350) level.enter.draw(); level.exit.drawAndCheck(); }; level.customTopLayer = () => { //exit room glow ctx.fillStyle = "rgba(0,255,255,0.05)" ctx.fillRect(1625, -350, 375, 350) //dark ctx.fillStyle = "rgba(0,0,0,0.2)" ctx.fillRect(500, -100, 1125, 175); }; // spawn.mapRect(1025, -675, 300, 623); //crouch wall // spawn.mapRect(625, -650, 1025, 550); spawn.mapRect(500, -650, 1125, 550); spawn.mapRect(-200, -650, 875, 300); spawn.mapRect(-2750, -2800, 2600, 4600); //left wall spawn.mapRect(2000, -2800, 2600, 4600); //right wall spawn.mapRect(-250, 50, 3500, 1750); //floor spawn.mapRect(-200, 0, 950, 100); spawn.mapRect(1575, 0, 500, 100); spawn.mapRect(-250, -2800, 3500, 2200); //roof spawn.mapRect(725, 12, 50, 25); spawn.mapRect(725, 25, 75, 25); spawn.mapRect(750, 38, 75, 25); spawn.mapRect(1525, 25, 75, 50); spawn.mapRect(1500, 38, 50, 25); spawn.mapRect(1550, 12, 50, 25); spawn.mapRect(1600, -1200, 500, 850); //exit roof }, jump() { //learn to jump m.addHealth(Infinity) level.setPosToSpawn(60, -50); //normal spawn spawn.mapRect(10, -10, 100, 20); //small platform for player level.exit.x = 1775; level.exit.y = -35; spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump simulation.zoomScale = 1400 //1400 is normal level.defaultZoom = 1400 simulation.zoomTransition(level.defaultZoom, 1) document.body.style.backgroundColor = level.trainingBackgroundColor let instruction = 0 level.trainingText(`hold down ${input.key.up.replace('Key', '').replace('Digit', '')} longer to jump higher`) level.custom = () => { if (instruction === 0 && m.pos.x > 300) { instruction++ level.trainingText(`hold down ${input.key.up.replace('Key', '').replace('Digit', '')} longer to jump higher`) } m.health = 1 //can't die //exit room ctx.fillStyle = "#f2f2f2" ctx.fillRect(1600, -400, 400, 400) level.enter.draw(); level.exit.drawAndCheck(); }; level.customTopLayer = () => { //dark ctx.fillStyle = "rgba(0,0,0,0.2)" ctx.fillRect(1000, 0, 450, 1800) //exit room glow ctx.fillStyle = "rgba(0,255,255,0.05)" ctx.fillRect(1600, -400, 400, 400) }; spawn.mapRect(-2750, -2800, 2600, 4600); //left wall spawn.mapRect(2000, -2800, 2600, 4600); //right wall spawn.mapRect(275, -350, 200, 375); spawn.mapRect(-250, 0, 1250, 1800); //floor spawn.mapRect(1450, 0, 1075, 1800); //floor spawn.mapRect(-250, -2800, 1250, 2200); //roof spawn.mapRect(1450, -2800, 1075, 2200); //roof spawn.mapVertex(375, 0, "150 0 -150 0 -100 -50 100 -50"); //base spawn.mapRect(1600, -1200, 500, 850); //exit roof spawn.mapRect(1600, -400, 50, 225); //exit room left upper wall //roof steps spawn.mapRect(1000, -650, 25, 25); spawn.mapRect(1000, -675, 50, 25); spawn.mapRect(1000, -700, 75, 25); spawn.mapRect(1000, -725, 100, 25); spawn.mapRect(1425, -650, 25, 25); spawn.mapRect(1400, -675, 50, 25); spawn.mapRect(1375, -700, 75, 25); spawn.mapRect(1350, -725, 100, 25); spawn.mapRect(1325, -750, 150, 25); spawn.mapRect(1300, -775, 150, 25); spawn.mapRect(1000, -750, 125, 25); spawn.mapRect(1275, -2800, 200, 2025); spawn.mapRect(975, -2800, 200, 2025); spawn.mapRect(1000, -775, 150, 25); }, hold() { //put block on button to open door m.addHealth(Infinity) level.setPosToSpawn(60, -50); //normal spawn spawn.mapRect(10, -10, 100, 20); //small platform for player level.exit.x = 1775; level.exit.y = -35; spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump simulation.zoomScale = 1400 //1400 is normal level.defaultZoom = 1400 simulation.zoomTransition(level.defaultZoom, 1) document.body.style.backgroundColor = level.trainingBackgroundColor spawn.bodyRect(1025, -75, 50, 50); //block to go on button const buttonDoor = level.button(500, 0) const door = level.door(1612.5, -175, 25, 190, 185, 3) let instruction = 0 level.trainingText(`activate your field with ${input.key.field.replace('Key', '').replace('Digit', '')} or right mouse`) level.custom = () => { if (instruction === 0 && input.field) { instruction++ level.trainingText(`activate your field with ${input.key.field.replace('Key', '').replace('Digit', '')} or right mouse
release your field on a block to pick it up`) } else if (instruction === 1 && m.isHolding) { instruction++ level.trainingText(`activate your field with ${input.key.field.replace('Key', '').replace('Digit', '')} or right mouse
release your field on a block to pick it up

drop the block on the red button to open the door`) } else if (instruction === 2 && !buttonDoor.isUp && Vector.magnitudeSquared(Vector.sub(body[0].position, buttonDoor.min)) < 10000) { instruction++ level.trainingText(`activate your field with ${input.key.field.replace('Key', '').replace('Digit', '')} or right mouse
release your field on a block to pick it up
drop the block on the red button to open the door
`) } //exit room ctx.fillStyle = "#f2f2f2" ctx.fillRect(1600, -400, 400, 400) level.enter.draw(); level.exit.drawAndCheck(); }; level.customTopLayer = () => { buttonDoor.query(); buttonDoor.draw(); if (buttonDoor.isUp) { door.isClosing = true } else { door.isClosing = false } door.openClose(); door.draw(); //exit room glow ctx.fillStyle = "rgba(0,255,255,0.05)" ctx.fillRect(1600, -400, 400, 400) }; spawn.mapRect(-2750, -2800, 2600, 4600); //left wall spawn.mapRect(2000, -2800, 2600, 4600); //right wall spawn.mapRect(-250, 50, 3500, 1750); //floor spawn.mapRect(-200, 0, 950, 100); spawn.mapRect(1575, 0, 500, 100); spawn.mapRect(-250, -2800, 3500, 2200); //roof spawn.mapRect(725, 12, 50, 25); spawn.mapRect(725, 25, 75, 25); spawn.mapRect(750, 38, 75, 25); spawn.mapRect(1525, 25, 75, 50); spawn.mapRect(1500, 38, 50, 25); spawn.mapRect(1550, 12, 50, 25); spawn.mapRect(1600, -1200, 500, 850); //exit roof spawn.mapRect(1600, -400, 50, 225); //exit room left upper wall }, throw () { //throw a block on button to open door m.addHealth(Infinity) level.setPosToSpawn(60, -50); //normal spawn spawn.mapRect(10, -10, 100, 20); //small platform for player level.exit.x = 1775; level.exit.y = -35; spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump simulation.zoomScale = 1400 //1400 is normal level.defaultZoom = 1400 simulation.zoomTransition(level.defaultZoom, 1) document.body.style.backgroundColor = level.trainingBackgroundColor spawn.bodyRect(1025, -75, 50, 50); //block to go on button const buttonDoor = level.button(1635, -400) const door = level.door(1612.5, -175, 25, 190, 185, 3) // activate your field with ${input.key.field.replace('Key', '').replace('Digit', '')} or right mouse let instruction = 0 level.trainingText(`pick up the block with your field`) level.custom = () => { if (instruction === 0 && m.isHolding) { instruction++ level.trainingText(`pick up the block with your field
hold your field down to charge up then release to throw a block`) } else if (instruction === 1 && m.throwCharge > 2) { instruction++ level.trainingText(`pick up the block with your field
hold your field down to charge up then release to throw a block

throw the block onto the button`) // the block at the button } else if (instruction === 2 && !buttonDoor.isUp && Vector.magnitudeSquared(Vector.sub(body[0].position, buttonDoor.min)) < 10000) { instruction++ level.trainingText(`pick up the block with your field
hold your field down to charge up then release to throw a block
throw the block onto the button
`) } //exit room ctx.fillStyle = "#f2f2f2" ctx.fillRect(1600, -400, 400, 400) level.enter.draw(); level.exit.drawAndCheck(); }; level.customTopLayer = () => { buttonDoor.query(); buttonDoor.draw(); if (buttonDoor.isUp) { door.isClosing = true } else { door.isClosing = false } door.openClose(); door.draw(); //exit room glow ctx.fillStyle = "rgba(0,255,255,0.05)" ctx.fillRect(1600, -400, 400, 400) }; spawn.mapRect(-2750, -2800, 2600, 4600); //left wall spawn.mapRect(2000, -2800, 2600, 4600); //right wall spawn.mapRect(-250, 50, 3500, 1750); //floor spawn.mapRect(-200, 0, 950, 100); spawn.mapRect(1575, 0, 500, 100); spawn.mapRect(-250, -2800, 3500, 2200); //roof spawn.mapRect(725, 12, 50, 25); spawn.mapRect(725, 25, 75, 25); spawn.mapRect(750, 38, 75, 25); spawn.mapRect(1525, 25, 75, 50); spawn.mapRect(1500, 38, 50, 25); spawn.mapRect(1550, 12, 50, 25); // spawn.mapRect(1600, -1200, 500, 850); //exit roof spawn.mapRect(1790, -600, 250, 225); //button left wall spawn.mapRect(1625, -400, 400, 50); spawn.mapRect(1600, -400, 50, 225); //exit room left upper wall }, throwAt() { //throw a block at mob to open door m.addHealth(Infinity) level.setPosToSpawn(60, -50); //normal spawn spawn.mapRect(10, -10, 100, 20); //small platform for player level.exit.x = 1775; level.exit.y = -35; spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump simulation.zoomScale = 1400 //1400 is normal level.defaultZoom = 1400 simulation.zoomTransition(level.defaultZoom, 1) document.body.style.backgroundColor = level.trainingBackgroundColor const door = level.door(1612.5, -175, 25, 190, 185, 3) let instruction = 0 level.trainingText(`throw the block at the mobs to open the door`) level.custom = () => { if (instruction === 0 && !mob.length) { instruction++ level.trainingText(`throw the block at the mobs to open the door`) } //exit room ctx.fillStyle = "#f2f2f2" ctx.fillRect(1600, -400, 400, 400) level.enter.draw(); level.exit.drawAndCheck(); }; level.customTopLayer = () => { if (mob.length > 0) { door.isClosing = true } else { door.isClosing = false } door.openClose(); door.draw(); //exit room glow ctx.fillStyle = "rgba(0,255,255,0.05)" ctx.fillRect(1600, -400, 400, 400) }; spawn.mapRect(-2750, -2800, 2600, 4600); //left wall spawn.mapRect(2000, -2800, 2600, 4600); //right wall spawn.mapRect(-250, 50, 3500, 1750); //floor spawn.mapRect(-200, 0, 950, 100); spawn.mapRect(1575, 0, 500, 100); spawn.mapRect(-250, -2800, 3500, 2200); //roof spawn.mapRect(725, 12, 50, 25); spawn.mapRect(725, 25, 75, 25); spawn.mapRect(750, 38, 75, 25); spawn.mapRect(1525, 25, 75, 50); spawn.mapRect(1500, 38, 50, 25); spawn.mapRect(1550, 12, 50, 25); // spawn.mapRect(1600, -1200, 500, 850); //exit roof // spawn.mapRect(1790, -600, 250, 225); //button left wall // spawn.mapRect(1625, -400, 400, 50); spawn.mapRect(1600, -400, 50, 225); //exit room left upper wall spawn.mapRect(1600, -600, 425, 250); spawn.bodyRect(1025, -75, 50, 50); //block to go on button spawn.starter(425, -350, 35) spawn.starter(800, -350, 44) }, fire() { //throw a block at mob to open door level.setPosToSpawn(60, -50); //normal spawn spawn.mapRect(10, -10, 100, 20); //small platform for player level.exit.x = 1775; level.exit.y = 15; spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump simulation.zoomScale = 1400 //1400 is normal level.defaultZoom = 1400 simulation.zoomTransition(level.defaultZoom, 1) document.body.style.backgroundColor = level.trainingBackgroundColor const door = level.door(1612.5, -125, 25, 190, 185, 3) const buttonDoor = level.button(400, 0) let instruction = 0 level.trainingText(`use your field to pick up the gun power up`) level.custom = () => { if (instruction === 0 && simulation.isChoosing) { instruction++ level.trainingText(`use your field to pick up the gun power up
choose a gun`) } else if (instruction === 1 && !simulation.isChoosing) { instruction++ level.trainingText(`use your field to pick up the gun power up
choose a gun

use the left mouse button to shoot the mobs`) } else if (instruction === 2 && mob.length === 0) { instruction++ level.trainingText(`use your field to pick up the gun power up
choose a gun
use the left mouse button to shoot the mobs

drop a block on the red button to open the door`) } else if (instruction === 3 && !door.isClosing) { instruction++ level.trainingText(`use your field to pick up the gun power up
choose a gun
use the left mouse button to shoot the mobs
put a block on the red button to open the door
`) } if (!powerUp.length) { //spawn ammo if you run out if (b.inventory.length && b.guns[b.activeGun].ammo === 0) powerUps.directSpawn(1300, -2000, "ammo", false); //spawn a gun power up if don't have one or a gun if (!b.inventory.length && !simulation.isChoosing) powerUps.directSpawn(1300, -2000, "gun", false); } //exit room ctx.fillStyle = "#f2f2f2" ctx.fillRect(1600, -350, 400, 400) level.enter.draw(); level.exit.drawAndCheck(); }; level.customTopLayer = () => { buttonDoor.query(); buttonDoor.draw(); if (buttonDoor.isUp) { door.isClosing = true } else { door.isClosing = false } door.openClose(); door.draw(); //exit room glow ctx.fillStyle = "rgba(0,255,255,0.05)" ctx.fillRect(1600, -350, 400, 400) //ammo tunnel shadow ctx.fillStyle = "rgba(0,0,0,0.4)" ctx.fillRect(1250, -2800, 100, 2200) }; spawn.mapRect(-2750, -2800, 2600, 4600); //left wall spawn.mapRect(2000, -2800, 2600, 4600); //right wall spawn.mapRect(-250, 50, 3500, 1750); //floor spawn.mapRect(-200, 0, 950, 100); spawn.mapRect(-150, -2800, 1400, 2200); //roof with tunnel for ammo spawn.mapRect(1350, -2800, 675, 2200); //ceiling steps spawn.mapRect(725, -588, 50, 25); spawn.mapRect(725, -600, 75, 25); spawn.mapRect(750, -612, 75, 25); spawn.mapRect(-275, -650, 1025, 87); spawn.mapRect(725, 12, 50, 25); spawn.mapRect(725, 25, 75, 25); spawn.mapRect(750, 38, 75, 25); spawn.mapRect(1600, -600, 425, 300); spawn.mapRect(1600, -400, 50, 275); powerUps.directSpawn(1300, -1500, "gun", false); spawn.starter(900, -300, 35) spawn.starter(1400, -400, 44) }, deflect() { //learn to jump m.addHealth(Infinity) level.setPosToSpawn(60, -50); //normal spawn spawn.mapRect(10, -10, 100, 20); //small platform for player level.exit.x = 1775; level.exit.y = -35; spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump simulation.zoomScale = 1400 //1400 is normal level.defaultZoom = 1400 simulation.zoomTransition(level.defaultZoom, 1) document.body.style.backgroundColor = level.trainingBackgroundColor let instruction = 0 // activate your field with ${input.key.field.replace('Key', '').replace('Digit', '')} or right mouse level.trainingText(`use your field to deflect the mobs`) level.custom = () => { if (instruction === 0 && m.pos.x > 1350) { instruction++ level.trainingText(`use your field to deflect the mobs`) } //teleport to start if hit if (m.immuneCycle > m.cycle) { m.energy = m.maxEnergy Matter.Body.setPosition(player, { x: 60, y: -50 }) } //spawn bullets if (!(simulation.cycle % 5)) { spawn.sniperBullet(660 + 580 * Math.random(), -2000, 10, 4); const who = mob[mob.length - 1] Matter.Body.setVelocity(who, { x: 0, y: 8 }); who.timeLeft = 300 } //exit room ctx.fillStyle = "#f2f2f2" ctx.fillRect(1600, -400, 400, 400) level.enter.draw(); level.exit.drawAndCheck(); }; level.customTopLayer = () => { //dark ctx.fillStyle = "rgba(0,0,0,0.05)" //exit room glow ctx.fillStyle = "rgba(0,255,255,0.05)" ctx.fillRect(1600, -400, 400, 400) //center falling bullets ctx.fillStyle = "rgba(255,0,255,0.013)" //pink? ctx.fillRect(650, -2800, 600, 2800) }; spawn.mapRect(-2750, -2800, 2600, 4600); //left wall spawn.mapRect(2000, -2800, 2600, 4600); //right wall spawn.mapRect(-250, 0, 3000, 1800); //floor spawn.mapRect(-250, -2800, 900, 2200); //roof spawn.mapRect(1250, -2800, 1275, 2200); //roof spawn.mapVertex(950, 0, "400 0 -400 0 -300 -50 300 -50"); //base spawn.mapRect(1600, -1200, 500, 850); //exit roof spawn.mapRect(1600, -400, 50, 225); //exit room left upper wall //spawn bullets on load to avoid rush for (let i = 0; i < 32; i++) { spawn.sniperBullet(660 + 580 * Math.random(), -2000 + 40 * i, 10, 4); const who = mob[mob.length - 1] Matter.Body.setVelocity(who, { x: 0, y: 8 }); who.timeLeft = 300 } }, heal() { //learn to heal m.addHealth(Infinity) m.health = 0; m.addHealth(0.25) document.getElementById("health").style.display = "inline" //show your health bar document.getElementById("health-bg").style.display = "inline" level.setPosToSpawn(60, -50); //normal spawn spawn.mapRect(10, -10, 100, 20); //small platform for player level.exit.x = 1775; level.exit.y = -35; spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump simulation.zoomScale = 1400 //1400 is normal level.defaultZoom = 1400 simulation.zoomTransition(level.defaultZoom, 1) document.body.style.backgroundColor = level.trainingBackgroundColor let instruction = 0 level.trainingText(`your health is displayed in the top left corner
use your field to pick up
until your health is full`) level.custom = () => { if (instruction === 0 && m.health === 1) { instruction++ level.trainingText(`use your field to pick up
until your health is full
`) } //exit room ctx.fillStyle = "#f2f2f2" ctx.fillRect(1600, -400, 400, 400) level.enter.draw(); level.exit.drawAndCheck(); }; level.customTopLayer = () => { if (m.health !== 1) { door.isClosing = true } else { door.isClosing = false } door.openClose(); door.draw(); //exit room glow ctx.fillStyle = "rgba(0,255,255,0.05)" ctx.fillRect(1600, -400, 400, 400) }; spawn.mapRect(-2750, -2800, 2600, 4600); //left wall spawn.mapRect(2000, -2800, 2600, 4600); //right wall spawn.mapRect(-250, 0, 3500, 1800); //floor spawn.mapRect(1575, 0, 500, 100); spawn.mapRect(-250, -2800, 3500, 2200); //roof spawn.mapRect(700, -8, 50, 25); spawn.mapRect(725, -16, 75, 25); spawn.mapRect(1375, -16, 50, 50); spawn.mapRect(1400, -8, 50, 25); spawn.mapRect(750, -24, 650, 100); powerUps.directSpawn(875, -40, "heal", false, null, 15); powerUps.directSpawn(1075, -50, "heal", false, null, 25); powerUps.directSpawn(1275, -65, "heal", false, null, 35); const door = level.door(1612.5, -175, 25, 190, 185, 3) spawn.mapRect(1600, -1200, 500, 850); //exit roof spawn.mapRect(1600, -400, 50, 225); //exit room left upper wall }, nailGun() { level.difficultyIncrease(1) //difficulty on training mode resets to zero with each new level level.setPosToSpawn(60, -50); //normal spawn spawn.mapRect(10, -10, 100, 20); //small platform for player level.exit.x = 1775; level.exit.y = -35; spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump simulation.zoomScale = 1400 //1400 is normal level.defaultZoom = 1400 simulation.zoomTransition(level.defaultZoom, 1) document.body.style.backgroundColor = level.trainingBackgroundColor b.removeAllGuns(); b.giveGuns("nail gun") b.guns[b.activeGun].ammo = 0 simulation.updateGunHUD(); const door = level.door(1612.5, -175, 25, 190, 185, 3) let instruction = 0 level.trainingText(`use your field to pick up
for your nail gun`) level.custom = () => { if (instruction === 0 && b.inventory.length && b.guns[b.activeGun].ammo > 0) { instruction++ level.trainingText(`use your field to pick up
for your nail gun

use the left mouse button to shoot the mobs`) } else if (instruction === 1 && mob.length === 0) { instruction++ level.trainingText(`use your field to pick up
for your nail gun
use the left mouse button to shoot the mobs
`) } //spawn ammo if you run out let isAmmo = false for (let i = 0; i < powerUp.length; i++) { if (powerUp[i].name === 'ammo') isAmmo = true } if (!isAmmo && b.inventory.length && b.guns[b.activeGun].ammo === 0) { powerUps.directSpawn(1300, -2000, "ammo", false); powerUps.directSpawn(1301, -2200, "ammo", false); } //exit room ctx.fillStyle = "#f2f2f2" ctx.fillRect(1600, -400, 400, 400) level.enter.draw(); level.exit.drawAndCheck(); }; level.customTopLayer = () => { if (mob.length > 0) { door.isClosing = true } else { door.isClosing = false } door.openClose(); door.draw(); //exit room glow ctx.fillStyle = "rgba(0,255,255,0.05)" ctx.fillRect(1600, -400, 400, 400) //ammo tunnel shadow ctx.fillStyle = "rgba(0,0,0,0.4)" ctx.fillRect(1250, -2800, 100, 2200) }; if (m.health < 1) { powerUps.directSpawn(1298, -3500, "heal", false, 23); powerUps.directSpawn(1305, -3000, "heal", false, 35); } for (let i = 0; i < 2; i++) { spawn.spinner(1300 + i, -3000 - 200 * i, 25 + 5 * i) Matter.Body.setVelocity(mob[mob.length - 1], { x: 0, y: 62 }); } spawn.mapRect(-2750, -2800, 2600, 4600); //left wall spawn.mapRect(2000, -2800, 2600, 4600); //right wall spawn.mapRect(-250, 50, 3500, 1750); //floor spawn.mapRect(-200, 0, 950, 100); spawn.mapRect(1575, 0, 500, 100); spawn.mapRect(-150, -2800, 1400, 2200); //roof with tunnel for ammo spawn.mapRect(1350, -2800, 675, 2200); spawn.mapRect(725, 12, 50, 25); spawn.mapRect(725, 25, 75, 25); spawn.mapRect(750, 38, 75, 25); spawn.mapRect(1525, 25, 75, 50); spawn.mapRect(1500, 38, 50, 25); spawn.mapRect(1550, 12, 50, 25); // spawn.mapRect(1600, -1200, 500, 850); //exit roof // spawn.mapRect(1790, -600, 250, 225); //button left wall // spawn.mapRect(1625, -400, 400, 50); spawn.mapRect(1600, -400, 50, 225); //exit room left upper wall spawn.mapRect(1600, -600, 425, 250); }, shotGun() { level.difficultyIncrease(1) //difficulty on training mode resets to zero with each new level level.setPosToSpawn(60, -50); //normal spawn spawn.mapRect(10, -10, 100, 20); //small platform for player level.exit.x = 1775; level.exit.y = -35; spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump simulation.zoomScale = 1400 //1400 is normal level.defaultZoom = 1400 simulation.zoomTransition(level.defaultZoom, 1) document.body.style.backgroundColor = level.trainingBackgroundColor b.removeAllGuns(); b.giveGuns("shotgun") // b.guns[b.activeGun].ammo = 0 // simulation.updateGunHUD(); const door = level.door(1612.5, -175, 25, 190, 185, 3) let instruction = 0 level.trainingText(`use your shotgun to clear the room of mobs`) level.custom = () => { if (instruction === 0 && mob.length === 0) { instruction++ level.trainingText(`use your shotgun to clear the room of mobs`) } //spawn ammo if you run out let isAmmo = false for (let i = 0; i < powerUp.length; i++) { if (powerUp[i].name === 'ammo') isAmmo = true } if (!isAmmo && b.inventory.length && b.guns[b.activeGun].ammo === 0) { powerUps.directSpawn(1300, -2000, "ammo", false); powerUps.directSpawn(1301, -2200, "ammo", false); } //exit room ctx.fillStyle = "#f2f2f2" ctx.fillRect(1600, -400, 400, 400) level.enter.draw(); level.exit.drawAndCheck(); }; level.customTopLayer = () => { if (mob.length > 0) { door.isClosing = true } else { door.isClosing = false } door.openClose(); door.draw(); //exit room glow ctx.fillStyle = "rgba(0,255,255,0.05)" ctx.fillRect(1600, -400, 400, 400) //ammo tunnel shadow ctx.fillStyle = "rgba(0,0,0,0.4)" ctx.fillRect(1250, -2800, 100, 2200) }; if (m.health < 1) { powerUps.directSpawn(1298, -3500, "heal", false, 23); powerUps.directSpawn(1305, -3000, "heal", false, 35); } for (let i = 0; i < 3; i++) { spawn.hopper(1300 + i, -3000 - 2000 * i, 25 + 5 * i) // Matter.Body.setVelocity(mob[mob.length - 1], { x: 0, y: 0 }); } spawn.mapRect(-2750, -2800, 2600, 4600); //left wall spawn.mapRect(2000, -2800, 2600, 4600); //right wall spawn.mapRect(-250, 50, 3500, 1750); //floor spawn.mapRect(-200, 0, 950, 100); spawn.mapRect(1575, 0, 500, 100); spawn.mapRect(-150, -2800, 1400, 2200); //roof with tunnel for ammo spawn.mapRect(1350, -2800, 675, 2200); spawn.mapRect(725, 12, 50, 25); spawn.mapRect(725, 25, 75, 25); spawn.mapRect(750, 38, 75, 25); spawn.mapRect(1525, 25, 75, 50); spawn.mapRect(1500, 38, 50, 25); spawn.mapRect(1550, 12, 50, 25); spawn.mapRect(1600, -400, 50, 225); //exit room left upper wall spawn.mapRect(1600, -600, 425, 250); }, superBall() { level.difficultyIncrease(1) //difficulty on training mode resets to zero with each new level level.setPosToSpawn(60, -50); //normal spawn spawn.mapRect(10, -10, 100, 20); //small platform for player level.exit.x = 1775; level.exit.y = -35; spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump simulation.zoomScale = 1400 //1400 is normal level.defaultZoom = 1400 simulation.zoomTransition(level.defaultZoom, 1) document.body.style.backgroundColor = level.trainingBackgroundColor b.removeAllGuns(); b.giveGuns("super balls") // b.guns[b.activeGun].ammo = 0 // simulation.updateGunHUD(); const door = level.door(1612.5, -175, 25, 190, 185, 3) let instruction = 0 level.trainingText(`use super balls to clear the room of mobs`) level.custom = () => { if (instruction === 0 && mob.length === 0) { instruction++ level.trainingText(`use super balls to clear the room of mobs`) } //spawn ammo if you run out let isAmmo = false for (let i = 0; i < powerUp.length; i++) { if (powerUp[i].name === 'ammo') isAmmo = true } if (!isAmmo && b.inventory.length && b.guns[b.activeGun].ammo === 0) { powerUps.directSpawn(1300, -2000, "ammo", false); powerUps.directSpawn(1301, -2200, "ammo", false); } //exit room ctx.fillStyle = "#f2f2f2" ctx.fillRect(1600, -400, 400, 400) level.enter.draw(); level.exit.drawAndCheck(); }; level.customTopLayer = () => { if (mob.length > 0) { door.isClosing = true } else { door.isClosing = false } door.openClose(); door.draw(); //exit room glow ctx.fillStyle = "rgba(0,255,255,0.05)" ctx.fillRect(1600, -400, 400, 400) //ammo tunnel shadow ctx.fillStyle = "rgba(0,0,0,0.2)" // ctx.fillRect(1225, -2800, 125, 2450) ctx.fillRect(-150, -2800, 1500, 2450); }; if (m.health < 1) { powerUps.directSpawn(1298, -3500, "heal", false, 23); powerUps.directSpawn(1305, -3000, "heal", false, 35); } for (let i = 0; i < 6; i++) { spawn.spawner(i * 230, -800) // Matter.Body.setVelocity(mob[mob.length - 1], { x: 0, y: 0 }); } spawn.mapVertex(510, -430, "725 0 725 80 -650 80 -650 -80 650 -80"); //upper room with mobs spawn.mapRect(-225, -2800, 1450, 2000); spawn.mapRect(1350, -2800, 675, 2450); spawn.mapRect(-2750, -2800, 2600, 4600); //left wall spawn.mapRect(2000, -2800, 2600, 4600); //right wall spawn.mapRect(-250, 50, 3500, 1750); //floor spawn.mapRect(-200, 0, 950, 100); spawn.mapRect(1575, 0, 500, 100); spawn.mapRect(725, 12, 50, 25); spawn.mapRect(725, 25, 75, 25); spawn.mapRect(750, 38, 75, 25); spawn.mapRect(1525, 25, 75, 50); spawn.mapRect(1500, 38, 50, 25); spawn.mapRect(1550, 12, 50, 25); spawn.mapRect(1600, -400, 50, 225); //exit room left upper wall }, matterWave() { //fire matter wave through the map to kill mosb level.difficultyIncrease(1) //difficulty on training mode resets to zero with each new level level.setPosToSpawn(60, -50); //normal spawn spawn.mapRect(10, -10, 100, 20); //small platform for player level.exit.x = 1775; level.exit.y = -35; spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump simulation.zoomScale = 1400 //1400 is normal level.defaultZoom = 1400 simulation.zoomTransition(level.defaultZoom, 1) document.body.style.backgroundColor = level.trainingBackgroundColor b.removeAllGuns(); b.giveGuns("matter wave") // b.guns[b.activeGun].ammo = 0 // simulation.updateGunHUD(); const door = level.door(1612.5, -175, 25, 190, 185, 3) let instruction = 0 level.trainingText(`use matter wave to clear the room of mobs`) level.custom = () => { if (instruction === 0 && mob.length === 0) { instruction++ level.trainingText(`use matter wave to clear the room of mobs`) } //spawn ammo if you run out let isAmmo = false for (let i = 0; i < powerUp.length; i++) { if (powerUp[i].name === 'ammo') isAmmo = true } if (!isAmmo && b.inventory.length && b.guns[b.activeGun].ammo === 0) { powerUps.directSpawn(1300, -2000, "ammo", false); powerUps.directSpawn(1301, -2200, "ammo", false); } //exit room ctx.fillStyle = "#f2f2f2" ctx.fillRect(1600, -400, 400, 400) level.enter.draw(); level.exit.drawAndCheck(); }; level.customTopLayer = () => { if (mob.length > 0) { door.isClosing = true } else { door.isClosing = false } door.openClose(); door.draw(); //exit room glow ctx.fillStyle = "rgba(0,255,255,0.05)" ctx.fillRect(1600, -400, 400, 400) //ammo tunnel shadow ctx.fillStyle = "rgba(0,0,0,0.2)" // ctx.fillRect(1225, -2800, 125, 2450) ctx.fillRect(-150, -2800, 1500, 2450); }; if (m.health < 1) { powerUps.directSpawn(1298, -3500, "heal", false, 23); powerUps.directSpawn(1305, -3000, "heal", false, 35); } for (let i = 0; i < 6; i++) { spawn.springer(i * 200, -800) // Matter.Body.setVelocity(mob[mob.length - 1], { x: 0, y: 0 }); } spawn.springer(1825, -330, 20); spawn.mapRect(1175, -850, 50, 500); //upper room with mobs spawn.mapRect(-225, -400, 1450, 50); spawn.mapRect(-225, -2800, 1450, 2000); spawn.mapRect(1350, -2800, 675, 2450); spawn.mapRect(-2750, -2800, 2600, 4600); //left wall spawn.mapRect(2000, -2800, 2600, 4600); //right wall spawn.mapRect(-250, 50, 3500, 1750); //floor spawn.mapRect(-200, 0, 950, 100); spawn.mapRect(1575, 0, 500, 100); spawn.mapRect(725, 12, 50, 25); spawn.mapRect(725, 25, 75, 25); spawn.mapRect(750, 38, 75, 25); spawn.mapRect(1525, 25, 75, 50); spawn.mapRect(1500, 38, 50, 25); spawn.mapRect(1550, 12, 50, 25); spawn.mapRect(1600, -400, 50, 225); //exit room left upper wall }, missile() { //fire a missile to kill mobs and trigger button level.difficultyIncrease(1) //difficulty on training mode resets to zero with each new level level.setPosToSpawn(60, -50); //normal spawn spawn.mapRect(10, -10, 100, 20); //small platform for player level.exit.x = 1775; level.exit.y = -35; spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 30); //exit bump simulation.zoomScale = 1400 //1400 is normal level.defaultZoom = 1400 simulation.zoomTransition(level.defaultZoom, 1) document.body.style.backgroundColor = level.trainingBackgroundColor b.removeAllGuns(); b.giveGuns("missiles") // b.guns[b.activeGun].ammo = 0 // simulation.updateGunHUD(); const buttonDoor = level.button(2500, 50) const door = level.door(1612.5, -175, 25, 190, 185, 3) let instruction = 0 level.trainingText(`use missiles to drop a block on the button`) level.custom = () => { if (instruction === 0 && mob.length === 0) { instruction++ level.trainingText(`use missiles to drop a block on the button`) } //spawn ammo if you run out let isAmmo = false for (let i = 0; i < powerUp.length; i++) { if (powerUp[i].name === 'ammo') isAmmo = true } if (!isAmmo && b.inventory.length && b.guns[b.activeGun].ammo === 0) { powerUps.directSpawn(1300, -2000, "ammo", false); powerUps.directSpawn(1301, -2200, "ammo", false); } //exit room ctx.fillStyle = "#f2f2f2" ctx.fillRect(1600, -400, 400, 400) level.enter.draw(); level.exit.drawAndCheck(); }; level.customTopLayer = () => { buttonDoor.query(); buttonDoor.draw(); if (buttonDoor.isUp) { door.isClosing = true } else { door.isClosing = false } door.openClose(); door.draw(); //exit room glow ctx.fillStyle = "rgba(0,255,255,0.05)" ctx.fillRect(1600, -400, 400, 400) //tunnel shadow ctx.fillStyle = "rgba(0,0,0,0.4)" ctx.fillRect(1250, -2800, 100, 2200) ctx.fillRect(1550, 25, 475, 25); }; if (m.health < 1) { powerUps.directSpawn(1298, -3500, "heal", false, 23); powerUps.directSpawn(1305, -3000, "heal", false, 35); } for (let i = 0; i < 10; i++) { spawn.springer(2100 + i * 100, -250) // Matter.Body.setVelocity(mob[mob.length - 1], { x: 0, y: 0 }); } spawn.mapRect(-2750, -2800, 2600, 4600); //left wall // spawn.mapRect(2000, -2800, 2600, 4600); //right wall spawn.mapRect(3050, -2800, 1550, 4600); spawn.mapRect(-250, 50, 3500, 1750); //floor spawn.mapRect(-200, 0, 950, 100); spawn.mapRect(-150, -2800, 1400, 2200); //roof with tunnel for ammo spawn.mapRect(1350, -2800, 675, 2200); spawn.mapRect(725, 12, 50, 25); spawn.mapRect(725, 25, 75, 25); spawn.mapRect(750, 38, 75, 25); // spawn.mapRect(1350, 0, 675, 30); spawn.mapRect(1550, 0, 475, 35); spawn.mapRect(1600, -400, 50, 225); //exit room left upper wall spawn.mapRect(1600, -600, 425, 250); spawn.mapRect(1975, -600, 50, 625); spawn.mapRect(2025, -2800, 1075, 2450); }, stack() { //stack blocks to get to exit level.difficultyIncrease(1) //difficulty on training mode resets to zero with each new level level.setPosToSpawn(60, -50); //normal spawn spawn.mapRect(10, -10, 100, 20); //small platform for player level.exit.x = 1775; level.exit.y = -685; spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump simulation.zoomScale = 1400 //1400 is normal level.defaultZoom = 1400 simulation.zoomTransition(level.defaultZoom, 1) document.body.style.backgroundColor = level.trainingBackgroundColor b.removeAllGuns(); let instruction = 0 level.trainingText(`use your field to stack the blocks`) level.custom = () => { if (instruction === 0 && m.pos.x > 1635) { instruction++ level.trainingText(`use your field to stack the blocks`) } //exit room ctx.fillStyle = "#f2f2f2" ctx.fillRect(1600, -1050, 400, 400) level.enter.draw(); level.exit.drawAndCheck(); }; level.customTopLayer = () => { //exit room glow ctx.fillStyle = "rgba(0,255,255,0.05)" ctx.fillRect(1600, -1050, 400, 400) //ammo tunnel shadow ctx.fillStyle = "rgba(0,0,0,0.4)" ctx.fillRect(250, -2800, 200, 1800) }; if (m.health < 1) { powerUps.directSpawn(298, -3500, "heal", false, 23); powerUps.directSpawn(305, -3000, "heal", false, 35); } for (let i = 0; i < 15; i++) { spawn.bodyRect(280, -2000 - 500 * i, 30 + 80 * Math.random(), 30 + 80 * Math.random()); } spawn.mapRect(-2750, -2800, 2600, 4600); //left wall spawn.mapRect(2000, -2800, 2600, 4600); //right wall spawn.mapRect(-250, 0, 3500, 1800); //floor spawn.mapRect(1600, -650, 450, 775); spawn.mapRect(-150, -2800, 400, 1800); //roof with tunnel for ammo spawn.mapRect(450, -2800, 1675, 1800); spawn.mapVertex(1300, 0, "400 0 -500 0 -300 -125 400 -125"); //base }, mine() { //kill mobs and tack their bodies level.difficultyIncrease(1) //difficulty on training mode resets to zero with each new level level.setPosToSpawn(300, -50); //normal spawn spawn.mapRect(250, -10, 100, 20); //small platform for player level.exit.x = 1775; level.exit.y = -685; spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump simulation.zoomScale = 1400 //1400 is normal level.defaultZoom = 1400 simulation.zoomTransition(level.defaultZoom, 1) document.body.style.backgroundColor = level.trainingBackgroundColor b.removeAllGuns(); b.giveGuns("mine") let instruction = 0 level.trainingText(`press the red button to spawn a mob`) const button = level.button(-100, -200) button.isUp = true spawn.mapRect(-150, -200, 240, 425); level.custom = () => { if (instruction === 0 && !button.isUp) { instruction++ level.trainingText(`press the red button to spawn a mob
turn the mobs into blocks`) } else if (instruction === 1 && body.length > 2) { instruction++ level.trainingText(`press the red button to spawn a mob
turn the mobs into blocks

use your field to stack the blocks`) } else if (instruction === 2 && m.pos.x > 1635) { instruction++ level.trainingText(`press the red button to spawn a mob
turn the mobs into blocks
use your field to stack the blocks
`) } //spawn ammo if you run out let isAmmo = false for (let i = 0; i < powerUp.length; i++) { if (powerUp[i].name === 'ammo') isAmmo = true } if (!isAmmo && b.inventory.length && b.guns[b.activeGun].ammo === 0) { powerUps.directSpawn(1300, -2000, "ammo", false); powerUps.directSpawn(1301, -2200, "ammo", false); } //exit room ctx.fillStyle = "#f2f2f2" ctx.fillRect(1600, -1050, 400, 400) level.enter.draw(); level.exit.drawAndCheck(); }; level.customTopLayer = () => { button.query(); button.draw(); if (!button.isUp) { if (button.isReady) { button.isReady = false spawn.exploder(335, -1700) Matter.Body.setVelocity(mob[mob.length - 1], { x: 0, y: 20 }); ctx.fillStyle = "rgba(255,0,0,0.9)" ctx.fillRect(550, -2800, 200, 1800) } } else { button.isReady = true } //exit room glow ctx.fillStyle = "rgba(0,255,255,0.05)" ctx.fillRect(1600, -1050, 400, 400) //ammo tunnel shadow ctx.fillStyle = "rgba(0,0,0,0.4)" ctx.fillRect(550, -2800, 200, 1800) }; if (m.health < 1) { powerUps.directSpawn(298, -3500, "heal", false, 23); powerUps.directSpawn(305, -3000, "heal", false, 35); } spawn.mapRect(-2750, -2800, 2600, 4600); //left wall spawn.mapRect(2000, -2800, 2600, 4600); //right wall spawn.mapRect(-250, 0, 3500, 1800); //floor spawn.mapRect(1600, -650, 450, 775); spawn.mapRect(-150, -2800, 700, 1800); //roof with tunnel for ammo spawn.mapRect(750, -2800, 1675, 1800); spawn.mapVertex(1300, 0, "400 0 -600 0 -300 -125 400 -125"); //base }, grenades() { //jump at the top of the elevator's path to go extra high level.difficultyIncrease(1) //difficulty on training mode resets to zero with each new level level.setPosToSpawn(0, -50); //normal spawn spawn.mapRect(-50, -10, 100, 20); //small platform for player level.exit.x = 1900; level.exit.y = -2835; spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump simulation.zoomScale = 1400 //1400 is normal level.defaultZoom = 1400 simulation.zoomTransition(level.defaultZoom, 1) document.body.style.backgroundColor = level.trainingBackgroundColor b.removeAllGuns(); b.giveGuns("grenades") const elevator1 = level.elevator(550, -100, 180, 25, -840, 0.003, { up: 0.05, down: 0.2 }) // x, y, width, height, maxHeight, force = 0.003, friction = { up: 0.01, down: 0.2 }) { elevator1.addConstraint(); const toggle1 = level.toggle(275, 0) //(x,y,isOn,isLockOn = true/false) const elevator2 = level.elevator(1400, -950, 180, 25, -2400, 0.0025) // x, y, width, height, maxHeight, force = 0.003, friction = { up: 0.01, down: 0.2 }) { elevator2.addConstraint(); const button2 = level.button(1000, -850) let instruction = 0 level.trainingText(`flip the switch to turn on the elevator`) level.custom = () => { if (instruction === 0 && elevator1.isOn) { instruction++ level.trainingText(`flip the switch to turn on the elevator
put a block on the button to active the elevator`) } else if (instruction === 1 && elevator2.isOn) { instruction++ level.trainingText(`flip the switch to turn on the elevator
put a block on the button to active the elevator

hold jump before the elevator's apex to reach the exit`) } else if (instruction === 2 && m.pos.x > 1635) { instruction++ level.trainingText(`flip the switch to turn on the elevator
put a block on the button to active the elevator
hold jump before the elevator's apex to reach the exit
`) } //exit room ctx.fillStyle = "#f2f2f2" ctx.fillRect(1725, -3100, 375, 300); level.enter.draw(); level.exit.drawAndCheck(); }; level.customTopLayer = () => { toggle1.query(); if (!toggle1.isOn) { if (elevator1.isOn) { elevator1.isOn = false elevator1.frictionAir = 0.2 elevator1.addConstraint(); } } else if (!elevator1.isOn) { elevator1.isOn = true elevator1.isUp = false elevator1.removeConstraint(); elevator1.frictionAir = 0.2 //elevator.isUp ? 0.01 : 0.2 } if (elevator1.isOn) { elevator1.move(); ctx.fillStyle = "#444" } else { ctx.fillStyle = "#aaa" } ctx.fillRect(640, -825, 1, 745) button2.query(); button2.draw(); if (button2.isUp) { if (elevator2.isOn) { elevator2.isOn = false elevator2.frictionAir = 0.2 elevator2.addConstraint(); } } else if (!elevator2.isOn) { elevator2.isOn = true elevator2.isUp = false elevator2.removeConstraint(); elevator2.frictionAir = 0.2 //elevator.isUp ? 0.01 : 0.2 } if (elevator2.isOn) { elevator2.move(); ctx.fillStyle = "#444" } else { ctx.fillStyle = "#aaa" } ctx.fillRect(1490, -2300, 1, 1375) //exit room glow ctx.fillStyle = "rgba(0,255,255,0.05)" ctx.fillRect(1725, -3100, 375, 300); //shadows ctx.fillStyle = "rgba(0,0,0,0.05)" ctx.fillRect(-150, -250, 300, 250); let grd = ctx.createLinearGradient(0, -150, 0, -2300); grd.addColorStop(0, "rgba(0,0,0,0.35)"); grd.addColorStop(1, "rgba(0,0,0,0)"); ctx.fillStyle = grd //"rgba(0,0,100,0.01)" ctx.fillRect(-200, -2300, 1825, 2300); }; if (m.health < 1) { powerUps.directSpawn(298, -3500, "heal", false, 23); powerUps.directSpawn(305, -3000, "heal", false, 35); } spawn.mapRect(-2750, -4800, 2600, 6600); //left wall spawn.mapRect(1600, -2800, 3000, 4600); //right wall spawn.mapRect(-150, -4800, 300, 4550); spawn.mapRect(2125, -4775, 2475, 2050); spawn.mapRect(-250, 0, 3500, 1800); //floor spawn.mapRect(750, -850, 950, 950); spawn.mapRect(125, -275, 25, 100); spawn.mapRect(2100, -3150, 50, 350); spawn.mapRect(1725, -3150, 50, 175); spawn.mapRect(1725, -3150, 425, 50); spawn.nodeGroup(1200, -1500, "grenadier", 7); }, harpoon() { //jump at the top of the elevator's path to go extra high level.difficultyIncrease(1) //difficulty on training mode resets to zero with each new level level.setPosToSpawn(0, -50); //normal spawn spawn.mapRect(-50, -10, 100, 20); //small platform for player level.exit.x = 1900; level.exit.y = -2835; spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump simulation.zoomScale = 1400 //1400 is normal level.defaultZoom = 1400 simulation.zoomTransition(level.defaultZoom, 1) document.body.style.backgroundColor = level.trainingBackgroundColor b.removeAllGuns(); b.giveGuns("harpoon") let instruction = 0 level.trainingText(`climb up to the exit`) level.custom = () => { if (instruction === 0 && m.pos.x > 1635) { instruction++ level.trainingText(`climb up to the exit`) } //exit room ctx.fillStyle = "#f2f2f2" ctx.fillRect(1725, -3100, 375, 300); level.enter.draw(); level.exit.drawAndCheck(); }; level.customTopLayer = () => { //exit room glow ctx.fillStyle = "rgba(0,255,255,0.05)" ctx.fillRect(1725, -3100, 375, 300); //shadows ctx.fillStyle = "rgba(0,90,100,0.05)" ctx.fillRect(-150, -250, 300, 250); let grd = ctx.createLinearGradient(0, -150, 0, -2300); grd.addColorStop(0, "rgba(0,90,100,0.35)"); grd.addColorStop(1, "rgba(0,90,100,0)"); ctx.fillStyle = grd //"rgba(0,0,100,0.01)" ctx.fillRect(-200, -2300, 1825, 2300); vanish1.query(); vanish2.query(); vanish3.query(); vanish4.query(); vanish5.query(); vanish6.query(); vanish7.query(); vanish8.query(); vanish9.query(); vanish10.query(); vanish11.query(); vanish12.query(); }; const vanish1 = level.vanish(175, -325, 175, 25); //x, y, width, height, hide = { x: 0, y: 100 } //hide should just be somewhere behind the map so the player can't see it const vanish2 = level.vanish(525, -625, 175, 25); const vanish3 = level.vanish(1125, -1125, 175, 25); const vanish4 = level.vanish(1500, -1450, 100, 25); const vanish5 = level.vanish(1125, -1675, 175, 25); const vanish6 = level.vanish(750, -1950, 175, 25); const vanish7 = level.vanish(550, -1950, 175, 25); const vanish8 = level.vanish(350, -1950, 175, 25); const vanish9 = level.vanish(150, -1950, 175, 25); const vanish10 = level.vanish(325, -2300, 200, 25); const vanish11 = level.vanish(725, -2550, 100, 25); const vanish12 = level.vanish(1125, -2700, 150, 25); if (m.health < 1) { powerUps.directSpawn(298, -3500, "heal", false, 23); powerUps.directSpawn(305, -3000, "heal", false, 35); } spawn.mapRect(-2750, -4800, 2600, 6600); //left wall spawn.mapRect(1600, -2800, 3000, 4600); //right wall spawn.mapRect(-150, -4800, 300, 4550); spawn.mapRect(2125, -4775, 2475, 2050); spawn.mapRect(-250, 0, 3500, 1800); //floor spawn.mapRect(750, -850, 950, 950); spawn.mapRect(125, -275, 25, 100); spawn.mapRect(2100, -3150, 50, 350); spawn.mapRect(1725, -3150, 50, 175); spawn.mapRect(1725, -3150, 425, 50); spawn.grower(250, -375); spawn.grower(1000, -900) spawn.grower(1475, -925); spawn.grower(275, -2000); spawn.grower(650, -2000); spawn.grower(1475, -975); spawn.grower(1575, -1525); spawn.grower(1700, -2850); }, trainingTemplate() { //learn to crouch m.addHealth(Infinity) document.getElementById("health").style.display = "none" //hide your health bar document.getElementById("health-bg").style.display = "none" level.setPosToSpawn(60, -50); //normal spawn spawn.mapRect(10, -10, 100, 20); //small platform for player level.exit.x = 1775; level.exit.y = -35; spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump simulation.zoomScale = 1400 //1400 is normal level.defaultZoom = 1400 simulation.zoomTransition(level.defaultZoom, 1) document.body.style.backgroundColor = level.trainingBackgroundColor let instruction = 0 level.trainingText(`press ${input.key.down.replace('Key', '').replace('Digit', '')} to crouch`) level.custom = () => { if (instruction === 0 && input.down) { instruction++ level.trainingText(`press ${input.key.down.replace('Key', '').replace('Digit', '')} to crouch`) } //exit room ctx.fillStyle = "#f2f2f2" ctx.fillRect(1600, -400, 400, 400) level.enter.draw(); level.exit.drawAndCheck(); }; level.customTopLayer = () => { //exit room glow ctx.fillStyle = "rgba(0,255,255,0.05)" ctx.fillRect(1600, -400, 400, 400) }; spawn.mapRect(-2750, -2800, 2600, 4600); //left wall spawn.mapRect(2000, -2800, 2600, 4600); //right wall spawn.mapRect(-250, 50, 3500, 1750); //floor spawn.mapRect(-200, 0, 950, 100); spawn.mapRect(1575, 0, 500, 100); spawn.mapRect(-250, -2800, 3500, 2200); //roof spawn.mapRect(725, 12, 50, 25); spawn.mapRect(725, 25, 75, 25); spawn.mapRect(750, 38, 75, 25); spawn.mapRect(1525, 25, 75, 50); spawn.mapRect(1500, 38, 50, 25); spawn.mapRect(1550, 12, 50, 25); spawn.mapRect(1600, -1200, 500, 850); //exit roof spawn.mapRect(1600, -400, 50, 225); //exit room left upper wall }, };