diff --git a/js/bullet.js b/js/bullet.js index 77c9e2e..2141f4f 100644 --- a/js/bullet.js +++ b/js/bullet.js @@ -164,23 +164,25 @@ const b = { } } }, - explosion(where, radius) { - radius *= mod.explosionRadius - // typically explode is used for some bullets with .onEnd - //add dmg to draw queue - game.drawList.push({ + explosion(where, radius) { // typically explode is used for some bullets with .onEnd + let dist, sub, knock; + let dmg = radius * 0.01; + if (mod.isExplosionHarm) radius *= 1.35 + if (mod.isSmallExplosion) { + radius *= 0.5 + dmg *= 1.5 + } + + game.drawList.push({ //add dmg to draw queue x: where.x, y: where.y, radius: radius, color: "rgba(255,25,0,0.6)", time: game.drawTime }); - let dist, sub, knock; - let dmg = radius * 0.01; const alertRange = 100 + radius * 2; //alert range - //add alert to draw queue - game.drawList.push({ + game.drawList.push({ //add alert to draw queue x: where.x, y: where.y, radius: alertRange, @@ -193,8 +195,12 @@ const b = { dist = Vector.magnitude(sub); if (dist < radius) { - if (!(mod.isImmuneExplosion && mech.energy > 0.75)) { - mech.damage(radius * 0.0001); //normal player damage from explosions + if (!(mod.isImmuneExplosion && mech.energy > 0.97)) { + if (mod.isExplosionHarm) { + mech.damage(radius * 0.0004); //300% more player damage from explosions + } else { + mech.damage(radius * 0.0001); //normal player damage from explosions + } mech.drop(); } knock = Vector.mult(Vector.normalise(sub), -Math.sqrt(dmg) * player.mass * 0.015); @@ -276,8 +282,13 @@ const b = { bullet[me].lookFrequency = Math.floor(21 + Math.random() * 7); bullet[me].onEnd = function () { b.explosion(this.position, this.explodeRad * size); //makes bullet do explosive damage at end - for (let i = 0; i < spawn; i++) { - b.missile(this.position, 2 * Math.PI * Math.random(), 0, 0.7 * size) + if (spawn) { + for (let i = 0; i < mod.recursiveMissiles; i++) { + if (0.3 - 0.03 * i > Math.random()) { + b.missile(this.position, this.angle + Math.PI + 0.5 * (Math.random() - 0.5), 0, 0.33 + size, mod.recursiveMissiles) + break; + } + } } } bullet[me].onDmg = function () { @@ -340,8 +351,8 @@ const b = { //draw rocket ctx.beginPath(); - ctx.arc(this.position.x - Math.cos(this.angle) * (30 * size - 3) + (Math.random() - 0.5) * 4, - this.position.y - Math.sin(this.angle) * (30 * size - 3) + (Math.random() - 0.5) * 4, + ctx.arc(this.position.x - Math.cos(this.angle) * (25 * size - 3) + (Math.random() - 0.5) * 4, + this.position.y - Math.sin(this.angle) * (25 * size - 3) + (Math.random() - 0.5) * 4, 11 * size, 0, 2 * Math.PI); ctx.fillStyle = "rgba(255,155,0,0.5)"; ctx.fill(); @@ -350,7 +361,7 @@ const b = { ctx.beginPath(); ctx.arc(this.position.x - Math.cos(this.angle) * (30 * size - 3) + (Math.random() - 0.5) * 4, this.position.y - Math.sin(this.angle) * (30 * size - 3) + (Math.random() - 0.5) * 4, - 11 * size, 0, 2 * Math.PI); + 2 + 9 * size, 0, 2 * Math.PI); ctx.fillStyle = "rgba(255,155,0,0.5)"; ctx.fill(); } @@ -1042,7 +1053,7 @@ const b = { onEnd() {}, do() { if (this.lastLookCycle < game.cycle) { - this.lastLookCycle = game.cycle + 80 - this.isUpgraded * 40 + this.lastLookCycle = game.cycle + 80 - this.isUpgraded * 50 let target for (let i = 0, len = mob.length; i < len; i++) { const dist = Vector.magnitudeSquared(Vector.sub(this.position, mob[i].position)); @@ -1107,7 +1118,7 @@ const b = { const radius = 6 + 7 * Math.random() const SPEED = 29 - radius * 0.5; //(mech.crouch ? 32 : 20) - radius * 0.7; const velocity = Vector.mult(Vector.normalise(Vector.sub(target, this.position)), SPEED) - b.foam(this.position, velocity, radius + 8 * this.isUpgraded) + b.foam(this.position, velocity, radius + 9 * this.isUpgraded) break; } } @@ -1207,7 +1218,7 @@ const b = { bestVertexDistance = dist } } - const dmg = b.dmgScale * (0.06 + 0.06 * this.isUpgraded); + const dmg = b.dmgScale * (0.06 + 0.075 * this.isUpgraded); this.lockedOn.damage(dmg); this.lockedOn.locatePlayer(); @@ -1257,7 +1268,7 @@ const b = { explode: 0, onDmg() { if (this.lockedOn) { - const explosionRadius = Math.min(170 + 110 * this.isUpgraded, Vector.magnitude(Vector.sub(this.position, mech.pos)) - 30) + const explosionRadius = Math.min(170 + 130 * this.isUpgraded, Vector.magnitude(Vector.sub(this.position, mech.pos)) - 30) if (explosionRadius > 60) { this.explode = explosionRadius // @@ -1995,7 +2006,7 @@ const b = { b.missile({ x: mech.pos.x + 40 * direction.x, y: mech.pos.y + 40 * direction.y - }, mech.angle + 0.06 * (1 - i), 0, 0.7, mod.babyMissiles) + }, mech.angle + 0.06 * (1 - i), 0, 0.7, mod.recursiveMissiles) bullet[bullet.length - 1].force.x += push.x * (i - 1); bullet[bullet.length - 1].force.y += push.y * (i - 1); } @@ -2011,7 +2022,7 @@ const b = { b.missile({ x: mech.pos.x + 40 * direction.x, y: mech.pos.y + 40 * direction.y - }, mech.angle, 0, 0.7, mod.babyMissiles) + }, mech.angle, 0, 0.7, mod.recursiveMissiles) bullet[bullet.length - 1].force.x += push.x * (i - 1); bullet[bullet.length - 1].force.y += push.y * (i - 1); } @@ -2024,7 +2035,7 @@ const b = { }, mech.angle + (0.5 - Math.random()) * (mech.crouch ? 0 : 0.2), -3 * (0.5 - Math.random()) + (mech.crouch ? 25 : -8) * b.fireCD, - 1, mod.babyMissiles) + 1, mod.recursiveMissiles) bullet[bullet.length - 1].force.y += 0.0006; //a small push down at first to make it seem like the missile is briefly falling } } @@ -2196,14 +2207,14 @@ const b = { suck(body, this.explodeRad * 2) suck(powerUp, this.explodeRad * 1.5) suck(bullet, this.explodeRad * 1.5) - suck([player], this.explodeRad * 1.5) + suck([player], this.explodeRad * 1.3) } else { mag = 0.1 suck(mob, this.explodeRad * 3) suck(body, this.explodeRad * 2) suck(powerUp, this.explodeRad * 1.5) suck(bullet, this.explodeRad * 1.5) - suck([player], this.explodeRad * 1.5) + suck([player], this.explodeRad * 1.3) } //keep bomb in place Matter.Body.setVelocity(this, { diff --git a/js/engine.js b/js/engine.js index 17daab8..2f066e9 100644 --- a/js/engine.js +++ b/js/engine.js @@ -159,6 +159,7 @@ function collisionChecks(event) { mod.mods[choose].count = 0; mod.mods[choose].remove(); // remove a random mod form the list of mods you have game.updateModHUD(); + mech.fieldCDcycle = mech.cycle + 30; //disable field so you can't pick up the ejected mod } if (mob[k].onHit) mob[k].onHit(k); diff --git a/js/index.js b/js/index.js index d58dcea..1d0c685 100644 --- a/js/index.js +++ b/js/index.js @@ -30,6 +30,12 @@ function shuffle(array) { return array; } +// shrink power up selection menu to find window height +if (screen.height < 800) { + document.getElementById("choose-grid").style.fontSize = "1em"; //1.3em is normal + if (screen.height < 600) document.getElementById("choose-grid").style.fontSize = "0.8em"; //1.3em is normal +} + //example https://landgreen.github.io/sidescroller/index.html? // &gun1=minigun&gun2=laser // &mod1=laser-bot&mod2=mass%20driver&mod3=overcharge&mod4=laser-bot&mod5=laser-bot&field=phase%20decoherence%20field&difficulty=2 diff --git a/js/level.js b/js/level.js index eccc23a..74f9363 100644 --- a/js/level.js +++ b/js/level.js @@ -20,6 +20,7 @@ const level = { // mod.giveMod("quantum immortality"); level.intro(); //starting level + // level.house() // level.testing(); //not in rotation // level.template() //not in rotation // level.testChamber() //less mobs, more puzzle @@ -35,8 +36,6 @@ const level = { // level.newLevel() //fan level // level.basement(); //fan level // level.stronghold() //fan level - - } else { spawn.setSpawnList(); //picks a couple mobs types for a themed random mob spawns // spawn.pickList = ["focuser", "focuser"] @@ -75,6 +74,488 @@ const level = { //****************************************************************************************************************** //****************************************************************************************************************** //****************************************************************************************************************** + + house() { + 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 = 9700; + level.exit.y = 2560; + level.defaultZoom = 1800 + game.zoomTransition(level.defaultZoom) + document.body.style.backgroundColor = "#969696" + + level.fillBG.push({ //lampadaire + x: 624, + y: -1150, + width: 28, + height: 1075, + color: "rgb(77, 76, 76)" + }); + //tele + level.fillBG.push({ //zone 1 + x: 3420, + y: -380, + width: 285, + height: 40, + color: "#ababab" + }) + level.fillBG.push({ //poignée 1 + x: 3555, + y: -367.5, + width: 15, + height: 15, + color: "#474747" + }) + level.fillBG.push({ //entre-deux 1 + x: 3418, + y: -344, + width: 288, + height: 8, + color: "#474747" + }) + level.fillBG.push({ //zone 2 + x: 3420, + y: -340, + width: 285, + height: 40, + color: "#ababab" + }) + level.fillBG.push({ //poignée 2 + x: 3555, + y: -327.5, + width: 15, + height: 15, + color: "#474747" + }) + level.fillBG.push({ //entre-deux 2 + x: 3418, + y: -304, + width: 288, + height: 8, + color: "#474747" + }) + level.fillBG.push({ //zone 3 + x: 3420, + y: -300, + width: 285, + height: 45, + color: "#ababab" + }) + level.fillBG.push({ //poignée 3 + x: 3555, + y: -285, + width: 15, + height: 15, + color: "#474747" + }) + level.fillBG.push({ //door bathroom + x: 3800, + y: -1275, + width: 250, + height: 425, + color: "rgba(141, 141, 141,1)", + }) + level.fillBG.push({ //door bathroom //top border + x: 3800, + y: -1275, + width: 250, + height: 3, + color: "#000", + }) + level.fillBG.push({ //door bathroom //right border + x: 4048, + y: -1275, + width: 3, + height: 425, + color: "#000", + }) + level.fillBG.push({ //door bathroom //left border + x: 3800, + y: -1275, + width: 3, + height: 425, + color: "#000", + }) + level.fillBG.push({ //poignée door bathroom + x: 3830, + y: -1050, + width: 35, + height: 10, + color: "#000", + }) + level.fillBG.push({ //background bathroom + x: 4050, + y: -1425, + width: 1125, + height: 600, + // color:"#c1d7db" + color: "rgba(225, 242, 245,0.6)" + }) + level.fillBG.push({ //window + x: 1736, + y: -1300, + width: 3, + height: 150, + color: "#444" + }) + level.fillBG.push({ //window + x: 1650, + y: -1224, + width: 175, + height: 3, + color: "#444" + }) + let color = Math.random().toString(16).substr(-6); + level.fillBG.push({ //écran + x: 3375, + y: -625, + width: 375, + height: 175, + color: '#' + color + }) + level.fill.push({ //hidden zone + x: 2800, + y: -400, + width: 275, + height: 175, + color: "rgba(64,64,64,0.96)" + }) + + + function drawCarreaux(x, y, width, height) { + level.fillBG.push({ //carreaux + x: x, + y: y, + width: width, + height: height, + color: "rgba(166, 166, 166,0.8)" + }) + } + for (let i = 0; i < 28; i++) { + drawCarreaux(4050 + i * 40, -1425, 1, 600); + } + for (let i = 0; i < 15; i++) { + drawCarreaux(4050, -1425 + i * 40, 1125, 2); + } + + const part1 = Matter.Bodies.rectangle(4525, -455, 25, 200, { + density: 0.0005, + isNotHoldable: true, + }); + const part2 = Matter.Bodies.rectangle(4562, -435, 100, 25, { + density: 0.0005, + isNotHoldable: true, + }); + const part3 = Matter.Bodies.rectangle(4600, -402, 25, 91.5, { + density: 0.0005, + isNotHoldable: true, + }); + const part4 = Matter.Bodies.rectangle(5100, -455, 25, 200, { + density: 0.0005, + isNotHoldable: true, + }); + const part5 = Matter.Bodies.rectangle(5063, -435, 100, 25, { + density: 0.0005, + isNotHoldable: true, + }); + const part6 = Matter.Bodies.rectangle(5025, -402, 25, 91.5, { + density: 0.0005, + isNotHoldable: true, + }); + chair = Body.create({ + parts: [part1, part2, part3], + }); + chair2 = Body.create({ + parts: [part4, part5, part6], + }); + World.add(engine.world, [chair]); + World.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, -400 - 60, 34, 40, { + isNotHoldable: true, + }); + var chest = Matter.Bodies.rectangle(300, -400, 55, 80, { + isNotHoldable: true, + }); + var rightUpperArm = Matter.Bodies.rectangle(300 + 39, -400 - 15, 20, 40, { + isNotHoldable: true, + }); + var rightLowerArm = Matter.Bodies.rectangle(300 + 39, -400 + 25, 20, 60, { + isNotHoldable: true, + }); + var leftUpperArm = Matter.Bodies.rectangle(300 - 39, -400 - 15, 20, 40, { + isNotHoldable: true, + }); + var leftLowerArm = Matter.Bodies.rectangle(300 - 39, -400 + 25, 20, 60, { + isNotHoldable: true, + }); + var leftUpperLeg = Matter.Bodies.rectangle(300 - 20, -400 + 57, 20, 40, { + isNotHoldable: true, + }); + var leftLowerLeg = Matter.Bodies.rectangle(300 - 20, -400 + 97, 20, 60, { + isNotHoldable: true, + }); + var rightUpperLeg = Matter.Bodies.rectangle(300 + 20, -400 + 57, 20, 40, { + isNotHoldable: true, + }); + var rightLowerLeg = Matter.Bodies.rectangle(300 + 20, -400 + 97, 20, 60, { + isNotHoldable: true, + }); + + var person = Body.create({ + parts: [chest, head, leftLowerArm, leftUpperArm, + rightLowerArm, rightUpperArm, leftLowerLeg, + rightLowerLeg, leftUpperLeg, rightUpperLeg + ], + }); + World.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); + + level.custom = () => { + buttonBedroom.query(); + buttonBedroom.draw(); + if (buttonBedroom.isUp) { + if (hasAlreadyBeenActivated == false) { + doorBedroom.isOpen = true; + doorGrenier.isOpen = true; + voletLucarne1.isOpen = true; + voletLucarne2.isOpen = true; + voletLucarne3.isOpen = true; + voletLucarne4.isOpen = true; + voletLucarne5.isOpen = true; + voletLucarne6.isOpen = true; + } + } else { + doorBedroom.isOpen = false; + doorGrenier.isOpen = false; + voletLucarne1.isOpen = false; + voletLucarne2.isOpen = false; + voletLucarne3.isOpen = false; + voletLucarne4.isOpen = false; + voletLucarne5.isOpen = false; + voletLucarne6.isOpen = false; + if (hasAlreadyBeenActivated == false) { + hasAlreadyBeenActivated = true; + } + } + doorBedroom.openClose(); + doorGrenier.openClose(); + voletLucarne1.openClose(); + voletLucarne2.openClose(); + voletLucarne3.openClose(); + voletLucarne4.openClose(); + voletLucarne5.openClose(); + voletLucarne6.openClose(); + rotor.rotate(); + hazard.query(); + /// + grd = ctx.createRadialGradient(512.5, -1025, 5, 512.5, -1025, 100); + grd.addColorStop(0, "rgb(255, 199, 43)"); + grd.addColorStop(1, "#969696"); + 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, "#969696"); + 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 * game.g; + chair2.force.y += chair2.mass * game.g; + person.force.y += person.mass * game.g; + }; + level.customTopLayer = () => { + hazard.draw(); + doorBedroom.draw(); + doorGrenier.draw(); + voletLucarne1.draw(); + voletLucarne2.draw(); + voletLucarne3.draw(); + voletLucarne4.draw(); + voletLucarne5.draw(); + voletLucarne6.draw(); + }; + + //rez de chaussée + spawn.mapRect(-200, 0, 5200, 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, 250); + spawn.mapRect(2675, -475, 400, 100); + spawn.mapRect(2675, -475, 150, 250); + spawn.mapRect(4025, -850, 50, 175); //porte cuisine + /*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); + + //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, -1800, 50, 400); + 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 + //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(2475, -2150, 2900, -2150, 8); + 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(2975, -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) + + //Mobs + // spawn.mobBloc(3015, -315, 84.855, "#ffff"); + + + }, + + + testing() { level.custom = () => { level.playerExitCheck(); @@ -635,12 +1116,7 @@ const level = { level.custom = () => { level.playerExitCheck(); }; - // ctx.font = "30px Arial"; - // ctx.textAlign = "center"; - level.customTopLayer = () => { - // ctx.fillStyle = '#000'; - // ctx.fillText(`${(localSettings.runCount >>> 0).toString(2)}`, 2850, -530); - }; + level.customTopLayer = () => {}; const binary = (localSettings.runCount >>> 0).toString(2) const height = 25 const thick = 2 @@ -811,17 +1287,71 @@ const level = { powerUps.spawn(1900, -150, "heal", false); //starting gun powerUps.spawn(2050, -150, "heal", false); //starting gun // powerUps.spawn(2050, -150, "field", false); //starting gun - powerUps.spawnStartingPowerUps(2300, -150); + // localSettings.levelsClearedLastGame = 20 + if (localSettings.levelsClearedLastGame < 5) { + spawn.wireFoot(); + spawn.wireFootLeft(); + spawn.wireKnee(); + spawn.wireKneeLeft(); + spawn.wireHead(); + } else { + const say = [] + if (localSettings.runCount > 200) { //experienced + say.push( + "I've been here before...", + "How many times have I done this?", + ) + } else if (localSettings.runCount < 20) { //new + say.push( + "Am I still alive?", + "And I'm back here again...", + "Is this another simulation?", + "I'm alive...", + "Last time was a simulation. Is this one a simulation too?", + ) + } + if (game.difficultyMode < 2 && localSettings.levelsClearedLastGame > 10) { //too easy + say.push( + "That felt too easy.
Maybe I should increase the difficulty of the simulation.", + "That was fun, but maybe I should increase the difficulty of the simulation.", + "I should increase the difficulty of the simulation, that didn't feel realistic.", + ) + } else if (game.difficultyMode > 1 && localSettings.levelsClearedLastGame > 10) { //great run on a hard or why + say.push( + "I think I'm getting closer to to the end, but what will I find there?", + "I think I'm getting closer to something, but what?", + "I'm getting stronger.", + "What happens after I escape?", + ) + } else { //resolve + say.push( + "I'll try some different mods this time.", + "I've got to escape.", + "I'll find a way out.", + ) + } + game.makeTextLog(say[Math.floor(say.length * Math.random())], 1000) - spawn.wireFoot(); - spawn.wireFootLeft(); - spawn.wireKnee(); - spawn.wireKneeLeft(); - spawn.wireHead(); + const swapPeriod = 150 + const len = 30 + for (let i = 0; i < len; i++) { + setTimeout(function () { + game.wipe = function () { //set wipe to have trails + ctx.fillStyle = `rgba(221,221,221,${i*i*0.0005 +0.0025})`; + ctx.fillRect(0, 0, canvas.width, canvas.height); + } + }, (i) * swapPeriod); + } + + setTimeout(function () { + game.wipe = function () { //set wipe to normal + ctx.clearRect(0, 0, canvas.width, canvas.height); + } + }, len * swapPeriod); + } + powerUps.spawnStartingPowerUps(2300, -150); }, satellite() { - // level.chain(4025, -1175, 15, 20) - const elevator = level.platform(4210, -1325, 380, 30, -10) level.custom = () => { level.playerExitCheck(); @@ -2443,7 +2973,7 @@ const level = { buttonDoor.query(); buttonPlateformEnd.draw(); buttonPlateformEnd.query(); - hazard.query(); + // hazard.query(); //bug reported from discord? if (buttonDoor.isUp) { door.isOpen = false } else { @@ -3826,28 +4356,35 @@ const level = { } }, level(isFill) { - const growSpeed = 1 - if (isFill) { - if (this.height < this.maxHeight) { - this.height += growSpeed - this.min.y -= growSpeed + if (mech.isBodiesAsleep) { + const growSpeed = 1 + 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 } - } else if (this.height > 0) { - this.height -= growSpeed - this.min.y += growSpeed - this.max.y = this.min.y + this.height } } } }, - chain(x, y, len = 15, radius = 20, stiffness = 0.4, damping = 0.01) { + 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, y + 2 * radius * i, 12, radius, { + body[body.length] = Bodies.polygon(x + gap * unit.x * i, y + gap * unit.y * i, 12, radius, { inertia: Infinity }); } - for (let i = 1; i < len; i++) { + 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], @@ -3858,11 +4395,22 @@ const level = { cons[cons.length] = Constraint.create({ //pin first block to a point in space pointA: { x: x, - y: y - radius + y: y }, bodyB: body[body.length - len], - stiffness: stiffness, + stiffness: 1, damping: damping }); + 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 + }); + } }, }; \ No newline at end of file diff --git a/js/mob.js b/js/mob.js index d579395..7fec3d2 100644 --- a/js/mob.js +++ b/js/mob.js @@ -1042,7 +1042,7 @@ const mobs = { } } if (Math.random() < mod.isBotSpawner) b.randomBot(this.position, false) - if (mod.isExplodeMob) b.explosion(this.position, Math.min(450, Math.sqrt(this.mass + 3) * 80)) + if (mod.isExplodeMob) b.explosion(this.position, Math.min(425, Math.sqrt(this.mass + 3) * 70)) if (mod.nailsDeathMob) b.targetedNail(this.position, mod.nailsDeathMob, 40 + 7 * Math.random()) } else if (mod.isShieldAmmo && this.shield) { let type = "ammo" diff --git a/js/mods.js b/js/mods.js index 2dddce2..bd09bca 100644 --- a/js/mods.js +++ b/js/mods.js @@ -367,6 +367,22 @@ const mod = { mod.sporesOnDeath = 0; } }, + { + name: "impact shear", + description: "mobs release a nail when they die
nails target nearby mobs", + maxCount: 9, + count: 0, + allowed() { + return true + }, + requires: "", + effect: () => { + mod.nailsDeathMob++ + }, + remove() { + mod.nailsDeathMob = 0; + } + }, { name: "thermal runaway", description: "mobs explode when they die
be careful", @@ -384,19 +400,51 @@ const mod = { } }, { - name: "impact shear", - description: "mobs release 1-2 nails when they die
nails target nearby mobs", - maxCount: 9, + name: "trinitrotoluene", + description: "increase explosive damage by 50%
decrease explosive area by 71%", + maxCount: 1, count: 0, allowed() { - return true + return mod.haveGunCheck("missiles") || mod.haveGunCheck("flak") || mod.haveGunCheck("grenades") || mod.haveGunCheck("vacuum bomb") || mod.haveGunCheck("pulse") || mod.isMissileField || mod.boomBotCount > 1; }, - requires: "", + requires: "an explosive damage source", effect: () => { - mod.nailsDeathMob += 2 + mod.isSmallExplosion = true; }, remove() { - mod.nailsDeathMob = 0; + mod.isSmallExplosion = false; + } + }, + { + name: "ammonium nitrate", + description: "increase explosive area by 60%, but
you take 300% more harm from explosions", + maxCount: 1, + count: 0, + allowed() { + return mod.haveGunCheck("missiles") || mod.haveGunCheck("flak") || mod.haveGunCheck("grenades") || mod.haveGunCheck("vacuum bomb") || mod.haveGunCheck("pulse") || mod.isMissileField + }, + requires: "an explosive damage source", + effect: () => { + mod.isExplosionHarm = true; + }, + remove() { + mod.isExplosionHarm = false; + } + }, + { + name: "electric reactive armor", + description: "explosions do no harm
while your energy is full", + maxCount: 1, + count: 0, + allowed() { + return mod.haveGunCheck("missiles") || mod.haveGunCheck("flak") || mod.haveGunCheck("grenades") || mod.haveGunCheck("vacuum bomb") || mod.isMissileField || mod.isExplodeMob + }, + requires: "an explosive gun", + effect: () => { + mod.isImmuneExplosion = true; + }, + remove() { + mod.isImmuneExplosion = false; } }, { @@ -612,9 +660,9 @@ const mod = { // isNonRefundable: true, isCustomHide: true, allowed() { - return mod.totalBots() > 2 + return mod.totalBots() > 3 }, - requires: "3 or more bots", + requires: "at least 3 bots", effect() { b.removeAllGuns(); game.makeGunHUD(); @@ -1029,7 +1077,7 @@ const mod = { }, { name: "Bayesian statistics", - description: "20% chance to duplicate spawned power ups
after a collision, eject one of your mods", + description: "17% chance to duplicate spawned power ups
after a collision, eject one of your mods", maxCount: 1, count: 0, allowed() { @@ -1111,9 +1159,9 @@ const mod = { maxCount: 1, count: 0, allowed() { - return true + return !mod.isEnergyNoAmmo }, - requires: "", + requires: "not exciton-lattice", effect() { mod.isAmmoForGun = true; }, @@ -1145,9 +1193,9 @@ const mod = { maxCount: 1, count: 0, allowed() { - return !mod.isEnergyHealth + return !mod.isEnergyHealth && !mod.isEnergyNoAmmo }, - requires: "not mass-energy equivalence", + requires: "not mass-energy equivalence
not exciton-lattice", effect: () => { mod.isAmmoFromHealth = 0.023; }, @@ -1691,52 +1739,20 @@ const mod = { mod.isWaveReflect = false } }, - { - name: "high explosives", - description: "increase explosion damage by 20%
explosive area is 44% larger", - maxCount: 3, - count: 0, - allowed() { - return mod.haveGunCheck("missiles") || mod.haveGunCheck("flak") || mod.haveGunCheck("grenades") || mod.haveGunCheck("vacuum bomb") || mod.haveGunCheck("pulse") || mod.isMissileField; - }, - requires: "an explosive gun", - effect: () => { - mod.explosionRadius += 0.2; - }, - remove() { - mod.explosionRadius = 1; - } - }, - { - name: "electric reactive armor", - description: "explosions do no harm
while your energy is above 75%", - maxCount: 1, - count: 0, - allowed() { - return mod.haveGunCheck("missiles") || mod.haveGunCheck("flak") || mod.haveGunCheck("grenades") || mod.haveGunCheck("vacuum bomb") || (mod.haveGunCheck("pulse") && mech.maxEnergy > 1) || mod.isMissileField || mod.isExplodeMob - }, - requires: "an explosive gun", - effect: () => { - mod.isImmuneExplosion = true; - }, - remove() { - mod.isImmuneExplosion = false; - } - }, { name: "recursion", - description: "after missiles explode
they launch 1 smaller missile", - maxCount: 9, + description: "after missiles explode they have a
30% chance to launch a larger missile", + maxCount: 6, count: 0, allowed() { return mod.haveGunCheck("missiles") || mod.isMissileField }, requires: "missiles", effect() { - mod.babyMissiles++ + mod.recursiveMissiles++ }, remove() { - mod.babyMissiles = 0; + mod.recursiveMissiles = 0; } }, { @@ -2599,7 +2615,6 @@ const mod = { ], //variables use for gun mod upgrades fireRate: null, - explosionRadius: null, bulletSize: null, energySiphon: null, healthDrain: null, @@ -2651,7 +2666,7 @@ const mod = { isPlasmaRange: null, isRailNails: null, isFreezeMobs: null, - babyMissiles: null, + recursiveMissiles: null, isIceCrystals: null, throwChargeRate: null, isBlockStun: null, @@ -2721,5 +2736,7 @@ const mod = { nailInstantFireRate: null, isCapacitor: null, isEnergyNoAmmo: null, - isFreezeHarmImmune: null + isFreezeHarmImmune: null, + isSmallExplosion: null, + isExplosionHarm: null } \ No newline at end of file diff --git a/js/player.js b/js/player.js index dddd6f9..7813f22 100644 --- a/js/player.js +++ b/js/player.js @@ -490,13 +490,13 @@ const mech = { damage(dmg) { mech.lastHarmCycle = mech.cycle if (mod.isDroneOnDamage) { //chance to build a drone on damage from mod - const len = (dmg - 0.06 * Math.random()) * 40 + const len = Math.min((dmg - 0.06 * Math.random()) * 40, 40) for (let i = 0; i < len; i++) { if (Math.random() < 0.5) b.drone() //spawn drone } } if (mod.isEnergyHealth) { - mech.energy -= dmg * 1.2; //20% extra damage for energy as health for balance reasons + mech.energy -= dmg; if (mech.energy < 0 || isNaN(mech.energy)) { //taking deadly damage if (mod.isDeathAvoid && powerUps.reroll.rerolls) { powerUps.reroll.changeRerolls(-1) @@ -660,13 +660,6 @@ const mech = { mech.knee.x = (l / d) * (mech.foot.x - mech.hip.x) - (h / d) * (mech.foot.y - mech.hip.y) + mech.hip.x + offset; mech.knee.y = (l / d) * (mech.foot.y - mech.hip.y) + (h / d) * (mech.foot.x - mech.hip.x) + mech.hip.y; }, - // collisionImmune: false, - // beginCollisionImmune() { - - // }, - // endCollisionImmune() { - - // }, draw() { ctx.fillStyle = mech.fillColor; mech.walk_cycle += mech.flipLegs * mech.Vx; @@ -1362,7 +1355,7 @@ const mech = { }, mech.angle + (0.5 - Math.random()) * (mech.crouch ? 0 : 0.2), -3 * (0.5 - Math.random()) + (mech.crouch ? 25 : -8) * b.fireCD, - 1, mod.babyMissiles) + 1, mod.recursiveMissiles) } else if (mod.isIceField) { // mech.fieldCDcycle = mech.cycle + 17; // set cool down to prevent +energy from making huge numbers of drones mech.energy -= 0.04; @@ -1772,15 +1765,8 @@ const mech = { mech.fieldPhase = 0; mech.hold = function () { - // function expandField() { - // if (this.fieldRange < 2000) { - // this.fieldRange += 100 - // drawField(this.fieldRange) - // } - // } - function drawField(radius) { - radius *= 0.9 + 2.2 * mech.energy * mech.energy; + radius *= Math.min(4, 0.9 + 2.2 * mech.energy * mech.energy); const rotate = mech.cycle * 0.005; mech.fieldPhase += 0.5 - 0.5 * Math.sqrt(Math.max(0.01, Math.min(mech.energy, 1))); const off1 = 1 + 0.06 * Math.sin(mech.fieldPhase); diff --git a/js/powerup.js b/js/powerup.js index 4d6721b..411837e 100644 --- a/js/powerup.js +++ b/js/powerup.js @@ -455,7 +455,7 @@ const powerUps = { randomPowerUpCounter: 0, spawnBossPowerUp(x, y) { //boss spawns field and gun mod upgrades powerUps.randomPowerUpCounter++; - if (game.difficultyMode === 4) spawnPowerUps() //why mode gets a free power up chance + if (game.difficultyMode === 4) powerUps.spawn(x, y, "mod") //why mode gets a free mod const chanceToFail = Math.max(level.levelsCleared, 10) * 0.1 //1 until level 10, then 1.1, 1.2, 1.3, ... if (Math.random() * chanceToFail < powerUps.randomPowerUpCounter) { powerUps.randomPowerUpCounter = 0; @@ -499,11 +499,12 @@ const powerUps = { }, spawnStartingPowerUps(x, y) { //used for map specific power ups, mostly to give player a starting gun if (level.levelsCleared < 4) { //runs 4 times on all difficulty levels + if (game.difficultyMode === 4 && level.levelsCleared > 1) powerUps.spawn(x, y, "mod") //bonus power ups for clearing runs in the last game if (level.levelsCleared === 0 && !game.isCheating) { for (let i = 0; i < localSettings.levelsClearedLastGame / 5 - 1; i++) { - powerUps.spawn(x, y, "mod", false); //spawn a mod for every 5 levels cleared in last game + powerUps.spawn(mech.pos.x, mech.pos.y, "mod", false); //spawn a mod for every 5 levels cleared in last game } localSettings.levelsClearedLastGame = 0 //after getting bonus power ups reset run history localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage @@ -569,7 +570,7 @@ const powerUps = { !(mod.isEnergyNoAmmo && target === 'ammo') ) { powerUps.directSpawn(x, y, target, moving, mode) - if (mod.isBayesian && Math.random() < 0.2) powerUps.directSpawn(x, y, target, moving, mode) + if (mod.isBayesian && Math.random() < 0.17) powerUps.directSpawn(x, y, target, moving, mode) } }, }; \ No newline at end of file diff --git a/js/spawn.js b/js/spawn.js index 04f6743..38955bb 100644 --- a/js/spawn.js +++ b/js/spawn.js @@ -1146,18 +1146,20 @@ const spawn = { }); Matter.Body.setPosition(this, this.startingPosition); - ctx.beginPath(); - this.laser(this.vertices[0], this.angle + Math.PI / 3); - this.laser(this.vertices[1], this.angle + Math.PI); - this.laser(this.vertices[2], this.angle - Math.PI / 3); - ctx.strokeStyle = "#50f"; - ctx.lineWidth = 1.5; - ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]); - ctx.stroke(); // Draw it - ctx.setLineDash([0, 0]); - ctx.lineWidth = 20; - ctx.strokeStyle = "rgba(80,0,255,0.07)"; - ctx.stroke(); // Draw it + if (!this.isStunned) { + ctx.beginPath(); + this.laser(this.vertices[0], this.angle + Math.PI / 3); + this.laser(this.vertices[1], this.angle + Math.PI); + this.laser(this.vertices[2], this.angle - Math.PI / 3); + ctx.strokeStyle = "#50f"; + ctx.lineWidth = 1.5; + ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]); + ctx.stroke(); // Draw it + ctx.setLineDash([0, 0]); + ctx.lineWidth = 20; + ctx.strokeStyle = "rgba(80,0,255,0.07)"; + ctx.stroke(); // Draw it + } // this.laser(this.vertices[2], this.angle + Math.PI / 3); this.checkStatus(); }; diff --git a/todo.txt b/todo.txt index bf1dd82..d87ea93 100644 --- a/todo.txt +++ b/todo.txt @@ -1,6 +1,22 @@ +mod: recursion - gives missiles a 30% chance to spawn a larger missile when they explode +mod: electric reactive armor - immune to harm from explosions while energy is full (was 80%) + +mod: ammonium nitrate - explosions are 60% bigger, but they do 300% more damage to you +mod: trinitrotoluene - explosions are 50% smaller and do 71% more damage + ************** TODO - n-gon ************** +mod: radiation effects can spread to nearby mobs + +mod: foam is attracted to mobs + use a gravitational attraction model? + could foam be attracted to other foam bullets too? + or foam is only attracted to foam bullets that are stuck to mobs + is this too computationally intense? + name - static cling + could also do bremsstrahlung radiation like damage on attachment + change player color based on harm reduction standing wave harmonics mod - push things away