diff --git a/js/bullets.js b/js/bullets.js index 9e0a635..73ca1b0 100644 --- a/js/bullets.js +++ b/js/bullets.js @@ -78,6 +78,7 @@ const b = { modWaveHelix: null, isModSporeFollow: null, isModNailPoison: null, + isModEnergyHealth: null, modOnHealthChange() { //used with acid mod if (b.isModAcidDmg && mech.health > 0.8) { b.modAcidDmg = 0.5 @@ -557,15 +558,35 @@ const b = { b.isModEntanglement = false; } }, + { + name: "mass-energy equivalence", + description: "your energy replaces your health
you can't die if your energy is above zero", + maxCount: 1, + count: 0, + allowed() { + return !b.isModPiezo + }, + requires: "not piezoelectricity", + effect: () => { + mech.health = 0 + b.modOnHealthChange(); + mech.displayHealth(); + b.isModEnergyHealth = true; + }, + remove() { + b.isModEnergyHealth = false; + mech.health = mech.energy; + } + }, { name: "piezoelectricity", description: "colliding with mobs fills your energy
15% less harm from mob collisions", maxCount: 1, count: 0, allowed() { - return true + return !b.isModEnergyHealth }, - requires: "", + requires: "not mass-energy equivalence", effect() { b.isModPiezo = true; mech.energy = mech.fieldEnergyMax; @@ -678,7 +699,7 @@ const b = { } }, { - name: "mass-energy equivalence", + name: "pair production", description: "power ups overfill your energy
temporarily gain twice your maximum", maxCount: 1, count: 0, @@ -822,7 +843,7 @@ const b = { }, { name: "depleted uranium rounds", - description: `your bullets are +13% larger
increased mass and physical damage`, + description: `your bullets are +16% larger
increased mass and physical damage`, count: 0, maxCount: 9, allowed() { @@ -830,7 +851,7 @@ const b = { }, requires: "minigun, shotgun, super balls", effect() { - b.modBulletSize += 0.13 + b.modBulletSize += 0.16 }, remove() { b.modBulletSize = 1; @@ -2042,8 +2063,7 @@ const b = { }, onEnd() {}, do() { - //find mob targets - if (!(game.cycle % this.lookFrequency)) { + if (!(game.cycle % this.lookFrequency)) { //find mob targets this.closestTarget = null; this.lockedOn = null; let closeDist = Infinity; @@ -2061,8 +2081,8 @@ const b = { } } } - //accelerate towards mobs - if (this.lockedOn && this.lockedOn.alive) { + + if (this.lockedOn && this.lockedOn.alive) { //accelerate towards mobs this.force = Vector.mult(Vector.normalise(Vector.sub(this.lockedOn.position, this.position)), this.mass * this.thrust) } else if (b.isModSporeFollow && this.lockedOn !== undefined) { //move towards player //checking for undefined means that the spores don't go after the player until it has looked and not found a target @@ -2097,7 +2117,7 @@ const b = { friction: 0, frictionAir: 0.10, restitution: 0.3, - dmg: 0.2, //damage done in addition to the damage from momentum + dmg: 0.18, //damage done in addition to the damage from momentum lookFrequency: 10 + Math.floor(7 * Math.random()), endCycle: game.cycle + 120 * b.isModBulletsLastLonger, //Math.floor((1200 + 420 * Math.random()) * b.isModBulletsLastLonger), classType: "bullet", diff --git a/js/game.js b/js/game.js index 6394034..a3c8c0f 100644 --- a/js/game.js +++ b/js/game.js @@ -686,31 +686,30 @@ const game = { } }, checks() { - if (mech.pos.y > game.fallHeight) { // if 4000px deep - if (game.difficultyMode > 2) { - mech.death(); - } else { - Matter.Body.setVelocity(player, { - x: 0, - y: 0 - }); - Matter.Body.setPosition(player, { - x: level.enter.x + 50, - y: level.enter.y - 20 - }); - // Matter.Body.setPosition(player, { - // x: player.position.x, - // y: -7000 - // }); - // game.noCameraScroll() - - mech.energy = 0; - if (game.difficultyMode === 2) mech.damage(0.3); - if (game.difficultyMode === 1) mech.damage(0.1); - } - } - if (!(mech.cycle % 60)) { //once a second + if (mech.pos.y > game.fallHeight) { // if 4000px deep + if (game.difficultyMode > 2) { + mech.death(); + } else { + Matter.Body.setVelocity(player, { + x: 0, + y: 0 + }); + Matter.Body.setPosition(player, { + x: level.enter.x + 50, + y: level.enter.y - 20 + }); + // Matter.Body.setPosition(player, { + // x: player.position.x, + // y: -7000 + // }); + // game.noCameraScroll() + + if (game.difficultyMode === 2) mech.damage(0.3); + if (game.difficultyMode === 1) mech.damage(0.1); + mech.energy = 0; + } + } if (b.isModEnergyDamage) { document.getElementById("mod-capacitor").innerHTML = `(+${(mech.energy/0.05).toFixed(0)}%)` diff --git a/js/index.js b/js/index.js index 3b52c3d..187cbca 100644 --- a/js/index.js +++ b/js/index.js @@ -458,6 +458,35 @@ document.body.addEventListener("mousedown", (e) => { } }); +document.body.addEventListener("mouseenter", (e) => { //prevents mouse getting stuck when leaving the window + // console.log(e) + if (e.which === 1) { + game.mouseDown = true; + } else { + game.mouseDown = false; + } + + if (e.which === 3) { + game.mouseDownRight = true; + } else { + game.mouseDownRight = false; + } +}); +document.body.addEventListener("mouseleave", (e) => { //prevents mouse getting stuck when leaving the window + // console.log(e) + if (e.which === 1) { + game.mouseDown = true; + } else { + game.mouseDown = false; + } + + if (e.which === 3) { + game.mouseDownRight = true; + } else { + game.mouseDownRight = false; + } +}); + //keyboard input const keys = []; document.body.addEventListener("keydown", (e) => { @@ -537,14 +566,14 @@ function cycle() { } game.loop(); - if (isNaN(mech.health)) { - console.log(`mech.health = ${mech.health}`) - game.paused = true; - game.replaceTextLog = true; - build.pauseGrid() - document.body.style.cursor = "auto"; - alert("health is NaN, please report this bug to the discord \n https://discordapp.com/invite/2eC9pgJ") - } + // if (isNaN(mech.health) || isNaN(mech.energy)) { + // console.log(`mech.health = ${mech.health}`) + // game.paused = true; + // game.replaceTextLog = true; + // build.pauseGrid() + // document.body.style.cursor = "auto"; + // alert("health is NaN, please report this bug to the discord \n https://discordapp.com/invite/2eC9pgJ") + // } // for (let i = 0, len = loop.length; i < len; i++) { // loop[i]() // } diff --git a/js/level.js b/js/level.js index b8a32ac..1df4d51 100644 --- a/js/level.js +++ b/js/level.js @@ -16,10 +16,9 @@ const level = { if (level.levelsCleared === 0) { //this code only runs on the first level // level.difficultyIncrease(9) // b.giveGuns("vacuum bomb") - // mech.setField("pilot wave") - // mech.energy = 0.1; - // b.giveMod("negative feedback"); - // b.giveMod("photovoltaics"); + mech.setField("pilot wave") + // b.giveMod("energy"); + // b.giveMod("Born rule"); level.intro(); //starting level // level.testing(); diff --git a/js/player.js b/js/player.js index adb2689..c71cbd0 100644 --- a/js/player.js +++ b/js/player.js @@ -494,10 +494,12 @@ const mech = { } }, addHealth(heal) { - mech.health += heal * game.healScale; - if (mech.health > mech.maxHealth) mech.health = mech.maxHealth; - b.modOnHealthChange(); - mech.displayHealth(); + if (!b.isModEnergyHealth) { + mech.health += heal * game.healScale; + if (mech.health > mech.maxHealth) mech.health = mech.maxHealth; + b.modOnHealthChange(); + mech.displayHealth(); + } }, defaultFPSCycle: 0, //tracks when to return to normal fps collisionImmuneCycle: 0, //used in engine @@ -522,41 +524,73 @@ const mech = { } dmg *= mech.fieldDamageResistance - if (!b.modEnergyRegen) dmg *= 0.5 //0.22 + 0.78 * mech.energy //77% damage reduction at zero energy + if (b.modEnergyRegen === 0) dmg *= 0.5 //0.22 + 0.78 * mech.energy //77% damage reduction at zero energy if (b.isModEntanglement && b.inventory[0] === b.activeGun) { for (let i = 0, len = b.inventory.length; i < len; i++) { dmg *= 0.84 // 1 - 0.16 } } + if (b.isModEnergyHealth) { + mech.energy -= dmg; + if (mech.energy < 0 || isNaN(mech.energy)) { + if (b.isModDeathAvoid && !b.isModDeathAvoidOnCD) { //&& Math.random() < 0.5 + b.isModDeathAvoidOnCD = true; + mech.energy += dmg //undo the damage + if (mech.energy < 0.05) mech.energy = 0.05 + mech.collisionImmuneCycle = mech.cycle + 30 //disable this.collisionImmuneCycle bonus seconds - mech.health -= dmg; - if (mech.health < 0) { - if (b.isModDeathAvoid && !b.isModDeathAvoidOnCD) { //&& Math.random() < 0.5 - b.isModDeathAvoidOnCD = true; - mech.health += dmg //undo the damage - if (mech.health < 0.05) mech.health = 0.05 - mech.collisionImmuneCycle = mech.cycle + 30 //disable this.collisionImmuneCycle bonus seconds - - game.wipe = function () { //set wipe to have trails - ctx.fillStyle = "rgba(255,255,255,0.02)"; - ctx.fillRect(0, 0, canvas.width, canvas.height); - } - setTimeout(function () { - game.wipe = function () { //set wipe to normal - ctx.clearRect(0, 0, canvas.width, canvas.height); + game.wipe = function () { //set wipe to have trails + ctx.fillStyle = "rgba(255,255,255,0.02)"; + ctx.fillRect(0, 0, canvas.width, canvas.height); } - // game.replaceTextLog = true; - // game.makeTextLog("death avoided", 360); - b.isModDeathAvoidOnCD = false; - }, 3000); + setTimeout(function () { + game.wipe = function () { //set wipe to normal + ctx.clearRect(0, 0, canvas.width, canvas.height); + } + // game.replaceTextLog = true; + // game.makeTextLog("death avoided", 360); + b.isModDeathAvoidOnCD = false; + }, 3000); - return; - } else { - mech.health = 0; - mech.death(); - return; + return; + } else { + mech.health = 0; + mech.energy = 0; + mech.death(); + return; + } + } + } else { + mech.health -= dmg; + if (mech.health < 0 || isNaN(mech.health)) { + if (b.isModDeathAvoid && !b.isModDeathAvoidOnCD) { //&& Math.random() < 0.5 + b.isModDeathAvoidOnCD = true; + mech.health += dmg //undo the damage + if (mech.health < 0.05) mech.health = 0.05 + mech.collisionImmuneCycle = mech.cycle + 30 //disable this.collisionImmuneCycle bonus seconds + + game.wipe = function () { //set wipe to have trails + ctx.fillStyle = "rgba(255,255,255,0.02)"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + } + setTimeout(function () { + game.wipe = function () { //set wipe to normal + ctx.clearRect(0, 0, canvas.width, canvas.height); + } + // game.replaceTextLog = true; + // game.makeTextLog("death avoided", 360); + b.isModDeathAvoidOnCD = false; + }, 3000); + + return; + } else { + mech.health = 0; + mech.death(); + return; + } } } + b.modOnHealthChange(); mech.displayHealth(); document.getElementById("dmg").style.transition = "opacity 0s"; @@ -1891,63 +1925,130 @@ const mech = { } } }, - // { - // name: "pilot wave", - // description: "push stuff", - // isEasyToAim: false, - // effect: () => { - // game.replaceTextLog = true; //allow text over write - // mech.lastMouseInGame = { - // x: game.mouseInGame.x, - // y: game.mouseInGame.y - // } - // mech.drop(); - // mech.fieldPhase = 0; - // mech.hold = function () { - // if ((keys[32] || game.mouseDownRight && mech.fieldCDcycle < mech.cycle)) { //not hold but field button is pressed - // mech.grabPowerUp(); - // //disable if player is inside field + { + name: "pilot wave", + description: "use energy to push blocks with your mouse
energy drain is lower in your line of sight", + isEasyToAim: false, + effect: () => { + game.replaceTextLog = true; //allow text over write + mech.fieldPhase = 0; + mech.fieldPosition = { + x: game.mouseInGame.x, + y: game.mouseInGame.y + } + mech.lastFieldPosition = { + x: game.mouseInGame.x, + y: game.mouseInGame.y + } + mech.fieldOn = false; + mech.fieldRadius = 0; + mech.drop(); + mech.hold = function () { + if ((keys[32] || game.mouseDownRight && mech.fieldCDcycle < mech.cycle)) { //not hold but field button is pressed - // const radius = 100 - // if (mech.energy > 0.05) { - // // && Vector.magnitude(Vector.sub(game.mouseInGame, player.position)) > radius * 1.5 - // //find mouse velocity - // const diff = Vector.sub(game.mouseInGame, mech.lastMouseInGame) - // const velocity = Vector.mult(Vector.normalise(diff), Math.min(Vector.magnitude(diff), 60)) //limit velocity - // //find nearby blocks - // for (let i = 0, len = body.length; i < len; ++i) { - // if (Vector.magnitude(Vector.sub(body[i].position, game.mouseInGame)) < radius) { - // // Matter.Query.collides(body, bodies) - // Matter.Body.setVelocity(body[i], velocity); //give block mouse velocity - // body[i].force.y -= body[i].mass * game.g; //antigravity - // //maybe give blocks some weak attraction to mouse - // } - // } - // ctx.beginPath(); - // const rotate = mech.cycle * 0.008; - // mech.fieldPhase += 0.2 // - 0.5 * Math.sqrt(Math.min(mech.energy, 1)); - // const off1 = 1 + 0.06 * Math.sin(mech.fieldPhase); - // const off2 = 1 - 0.06 * Math.sin(mech.fieldPhase); - // ctx.beginPath(); - // ctx.ellipse(game.mouseInGame.x, game.mouseInGame.y, radius * off1, radius * off2, rotate, 0, 2 * Math.PI); - // // ctx.arc(game.mouseInGame.x, game.mouseInGame.y, this.fieldRange, 0, 2 * Math.PI); - // ctx.fillStyle = "#eef"; - // ctx.globalCompositeOperation = "difference"; - // ctx.fill(); - // ctx.strokeStyle = "#000"; - // ctx.lineWidth = 1; - // ctx.stroke(); - // ctx.globalCompositeOperation = "source-over"; - // } - // } - // mech.lastMouseInGame = { //constantly log last mouse position so you can calc mouse velocity - // x: game.mouseInGame.x, - // y: game.mouseInGame.y - // } - // mech.drawFieldMeter() - // } - // } - // }, + // if (Matter.Query.ray(map, game.mouseInGame, player.position).length === 0){ + + // } else { + // mech.fieldOn = false; + // } + + if (!mech.fieldOn) { + mech.fieldOn = true; + mech.fieldPosition = { //smooth the mouse position + x: game.mouseInGame.x, + y: game.mouseInGame.y + } + mech.lastFieldPosition = { //used to find velocity of field changes + x: mech.fieldPosition.x, + y: mech.fieldPosition.y + } + } else { + mech.lastFieldPosition = { //used to find velocity of field changes + x: mech.fieldPosition.x, + y: mech.fieldPosition.y + } + const smooth = 0.97 + mech.fieldPosition = { //smooth the mouse position + x: mech.fieldPosition.x * smooth + game.mouseInGame.x * (1 - smooth), + y: mech.fieldPosition.y * smooth + game.mouseInGame.y * (1 - smooth), + } + } + // Matter.Query.ray(map, game.mouseInGame, player.position).length === 0 + //make it so the field only works in line of sight + // make the field not get stuck on map when there in no line of site + // maybe track the last mouse position, and revert to smooting towards it when mouse leaves line of site + // if (Matter.Query.ray(map, mech.fieldPosition, player.position).length === 0) + + + + mech.grabPowerUp(); + //disable if player is inside field + + if (mech.energy > 0.01) { + // && Vector.magnitude(Vector.sub(game.mouseInGame, player.position)) > radius * 1.5 //disable effect when near player + //find mouse velocity + const diff = Vector.sub(mech.fieldPosition, mech.lastFieldPosition) + const speed = Vector.magnitude(diff) + const velocity = Vector.mult(Vector.normalise(diff), Math.min(speed, 60)) //limit velocity + let radius = Math.max(50, 250 - 1.5 * speed) //change radius proportional to mouse speed //run a smoothing function? + let isVisible = true + if (Matter.Query.ray(map, mech.fieldPosition, player.position).length !== 0) { + isVisible = false + radius *= 0.2 + } + smooth = 0.9 + mech.fieldRadius = mech.fieldRadius * smooth + radius * (1 - smooth) + + //find nearby blocks + for (let i = 0, len = body.length; i < len; ++i) { + if (Vector.magnitude(Vector.sub(body[i].position, mech.fieldPosition)) < mech.fieldRadius) { + // Matter.Query.collides(player, [body[i]]).length === 0) { //block is not touching player, for no flying + // (Matter.Query.ray(map, game.mouseInGame, player.position).length === 0 ? 1 : 4) + const DRAIN = speed * body[i].mass * 0.00002 * (isVisible ? 1 : 4) + if (mech.energy > DRAIN) { + mech.energy -= DRAIN; + Matter.Body.setVelocity(body[i], velocity); //give block mouse velocity + body[i].force.y -= body[i].mass * game.g; //remove gravity effects + } else { + mech.fieldOn = false + mech.fieldCDcycle = mech.cycle + 120; + mech.fieldRadius = 0 + break + } + } + } + ctx.beginPath(); + const rotate = mech.cycle * 0.008; + mech.fieldPhase += 0.2 // - 0.5 * Math.sqrt(Math.min(mech.energy, 1)); + const off1 = 1 + 0.06 * Math.sin(mech.fieldPhase); + const off2 = 1 - 0.06 * Math.sin(mech.fieldPhase); + ctx.beginPath(); + ctx.ellipse(mech.fieldPosition.x, mech.fieldPosition.y, 1.2 * mech.fieldRadius * off1, 1.2 * mech.fieldRadius * off2, rotate, 0, 2 * Math.PI); + // ctx.ellipse(game.mouseInGame.x, game.mouseInGame.y, radius * off1, radius * off2, -rotate, 0, 2 * Math.PI); + // ctx.arc(game.mouseInGame.x, game.mouseInGame.y, this.fieldRange, 0, 2 * Math.PI); + ctx.fillStyle = "#fff"; //"#eef"; + ctx.globalCompositeOperation = "exclusion"; //"exclusion" "difference"; + ctx.fill(); + ctx.globalCompositeOperation = "source-over"; + + ctx.beginPath(); + ctx.ellipse(mech.fieldPosition.x, mech.fieldPosition.y, 1.2 * mech.fieldRadius * off1, 1.2 * mech.fieldRadius * off2, rotate, 0, mech.energy * 2 * Math.PI); + ctx.strokeStyle = "#000"; + ctx.lineWidth = 4; + ctx.stroke(); + } else { + mech.fieldOn = false + mech.fieldCDcycle = mech.cycle + 120; + mech.fieldRadius = 0 + } + } else { + mech.fieldOn = false + mech.fieldRadius = 0 + } + mech.drawFieldMeter() + } + } + }, ], }; \ No newline at end of file diff --git a/js/powerups.js b/js/powerups.js index 2ffa226..9d655a8 100644 --- a/js/powerups.js +++ b/js/powerups.js @@ -47,10 +47,14 @@ const powerUps = { return 40 * Math.sqrt(0.1 + Math.random() * 0.5); }, effect() { - let heal = 0 - for (let i = 0; i < b.modRecursiveHealing; i++) heal += ((this.size / 40) ** 2) - if (heal > 0) game.makeTextLog("
  heal " + (Math.min(mech.maxHealth - mech.health, heal) * game.healScale * 100).toFixed(0) + "%", 300) - mech.addHealth(heal); + if (!b.isModEnergyHealth) { + let heal = 0 + for (let i = 0; i < b.modRecursiveHealing; i++) heal += ((this.size / 40) ** 2) + if (heal > 0) { + game.makeTextLog("
  heal " + (Math.min(mech.maxHealth - mech.health, heal) * game.healScale * 100).toFixed(0) + "%", 300) + mech.addHealth(heal); + } + } } }, ammo: { diff --git a/js/spawn.js b/js/spawn.js index 7f2f276..f36e92c 100644 --- a/js/spawn.js +++ b/js/spawn.js @@ -566,7 +566,7 @@ const spawn = { } toMe(body, this.position, this.eventHorizon) toMe(mob, this.position, this.eventHorizon) - toMe(bullet, this.position, this.eventHorizon) + // toMe(bullet, this.position, this.eventHorizon) } }; me.do = function () { @@ -826,7 +826,6 @@ const spawn = { x: x, y: y } - me.dmg = 0.14 * game.dmgScale; me.frictionAir = 0.03; // me.torque -= me.inertia * 0.002 Matter.Body.setDensity(me, 0.03); //extra dense //normal is 0.001 //makes effective life much larger @@ -920,11 +919,12 @@ const spawn = { if (!mech.isStealth) vertexCollision(where, look, [player]); if (best.who && best.who === player && mech.collisionImmuneCycle < mech.cycle) { mech.collisionImmuneCycle = mech.cycle + b.modCollisionImmuneCycles; //player is immune to collision damage for 30 cycles - mech.damage(this.dmg); + const dmg = 0.14 * game.dmgScale; + mech.damage(dmg); game.drawList.push({ //add dmg to draw queue x: best.x, y: best.y, - radius: this.dmg * 1500, + radius: dmg * 1500, color: "rgba(80,0,255,0.5)", time: 20 }); diff --git a/todo.txt b/todo.txt index ecc63ad..c702ef6 100644 --- a/todo.txt +++ b/todo.txt @@ -1,10 +1,10 @@ -mod - spores follow player -mod - nails do 66% extra damage over 6 seconds ************** TODO - n-gon ************** +mod - energy replaces your health, + field - pilot wave while mouse is down blocks (and mobs?) are move with the mouse players can do serious damage by flicking the mouse and firing blocks