From 2577d8a3e4b1dfef5ad0de5711a5d32996a2eb04 Mon Sep 17 00:00:00 2001 From: landgreen Date: Sun, 27 Oct 2019 16:40:00 -0700 Subject: [PATCH] added quantum immortaility --- index.html | 4 +- js/bullets.js | 44 +-- js/game.js | 36 ++- js/index.js | 3 + js/level.js | 12 +- js/player.js | 736 +++++++++++++++++++++++++++---------------------- js/powerups.js | 4 +- js/spawn.js | 12 +- style.css | 24 +- 9 files changed, 490 insertions(+), 385 deletions(-) diff --git a/index.html b/index.html index 7b18c8b..70da1f1 100644 --- a/index.html +++ b/index.html @@ -33,9 +33,7 @@
-
- Auto-Loading Heuristics -
+
diff --git a/js/bullets.js b/js/bullets.js index 5c92d0d..d51ad94 100644 --- a/js/bullets.js +++ b/js/bullets.js @@ -12,7 +12,7 @@ const b = { modHealthDrain: null, modNoAmmo: null, modBulletsLastLonger: null, - // modNonEuclidean: null, + modIsImmortal: null, setModDefaults() { b.modFireRate = 1; b.modExplosionRadius = 1; @@ -21,15 +21,15 @@ const b = { b.modHealthDrain = 0; b.modNoAmmo = 0; b.modBulletsLastLonger = 1; - // b.modNonEuclidean = false; + b.modIsImmortal = false; }, - modText: function () { - game.makeTextLog(`${b.mods[b.mod].name}
(left click)

${b.mods[b.mod].description}

`, 1200); - document.getElementById("mods").innerHTML = b.mods[b.mod].name + modText() { + if (b.mod !== null) game.makeTextLog(`${b.mods[b.mod].name}

${b.mods[b.mod].description}

`, 1200); + game.updateModHUD() }, mods: [{ name: "Auto-Loading Heuristics", - description: "your rate of fire 15% is faster", + description: "your rate of fire is 15% faster", effect: () => { b.mod = 0 b.modText(); @@ -40,7 +40,7 @@ const b = { }, { name: "Anti-Matter Cores", - description: "your explosions are larger and do more damage", + description: "your explosions are larger and more dangerous", effect: () => { b.mod = 1 b.modText(); @@ -68,7 +68,7 @@ const b = { effect: () => { b.mod = 3 b.modText(); - b.setModDefaults(); //good with laser, Nano-Scale Manufacturing, Standing Wave Harmonics, Phase Decoherence Field + b.setModDefaults(); //good with laser, and all fields b.modEnergySiphon = 0.2; } }, @@ -93,26 +93,26 @@ const b = { } }, { - name: "Anti-Decay Coating", - description: "your bullets last 25% longer", + name: "Decay Resistant Topology", + description: "your bullets last 30% longer", effect: () => { b.mod = 6 b.modText(); b.setModDefaults(); //good with: drones, super balls, spore, missiles, wave beam(range), rapid fire(range), flak(range) - b.modBulletsLastLonger = 1.25 + b.modBulletsLastLonger = 1.30 } }, - // { - // name: "Non-Euclidean Geometry", - // description: "after you fall loop back to the top of the map", - // have: false, - // effect: () => { - // b.mod = 7 - // b.modText(); - // b.setModDefaults(); //good with: drones, super balls, spore, missiles, wave beam(range), rapid fire(range), flak(range) - // b.modNonEuclidean = true - // } - // }, + { + name: "Quantum Immortality", + description: "after you die continue in an alternate reality with randomized abilities
", + effect: () => { + b.mod = 7 + b.modText(); + b.setModDefaults(); //good with: drones, super balls, spore, missiles, wave beam(range), rapid fire(range), flak(range) + b.modIsImmortal = true; + } + }, + // () => { // b.mod = 8; // game.makeTextLog("Relativistic Velocity
(left click)

Your bullets are effected extra by your own velocity

", 1200); diff --git a/js/game.js b/js/game.js index d922d65..d9f5cee 100644 --- a/js/game.js +++ b/js/game.js @@ -153,6 +153,16 @@ const game = { } game.boldActiveGunHUD(); }, + updateModHUD() { + let text = "" + if (mech.fieldMode !== 0) { + text += mech.fieldUpgrades[mech.fieldMode].name + if (b.mod !== null) text += "
" + b.mods[b.mod].name + } else if (b.mod !== null) { + text += b.mods[b.mod].name + } + document.getElementById("mods").innerHTML = text + }, makeTextLog(text, time = 180) { document.getElementById("text-log").innerHTML = text; document.getElementById("text-log").style.opacity = 1; @@ -250,10 +260,14 @@ const game = { requestAnimationFrame(cycle); } else { game.paused = true; - let text = "

PAUSED

" - // if (b.mod !== null) text+= - //output current mod, field, and gun info when paused - game.makeTextLog(text); + game.makeTextLog("

PAUSED

", 1); + // let text = "

PAUSED


" + // //output current mod, field, and gun info when paused + // if (mech.fieldMode !== 0) text += "

" + mech.fieldUpgrades[mech.fieldMode].name + "
" + mech.fieldUpgrades[mech.fieldMode].description + "

" + // if (b.mod !== null) text += "

" + b.mods[b.mod].name + "
" + b.mods[b.mod].description + "

" + // if (b.activeGun !== null) text += "

" + b.guns[b.activeGun].name + "
" + b.guns[b.activeGun].description + "

" + // text += "
" + // game.makeTextLog(text, 1); } } @@ -270,9 +284,9 @@ const game = { if (keys[70]) { //cycle fields with F if (mech.fieldMode === mech.fieldUpgrades.length - 1) { - mech.fieldUpgrades[0]() + mech.fieldUpgrades[0].effect() } else { - mech.fieldUpgrades[mech.fieldMode + 1]() + mech.fieldUpgrades[mech.fieldMode + 1].effect() } } if (keys[71]) { // give all guns with G @@ -361,8 +375,11 @@ const game = { }, wipe() { ctx.clearRect(0, 0, canvas.width, canvas.height); - // ctx.fillStyle = "#000"; + + // ctx.fillStyle = "rgba(255,255,255,1)"; + // ctx.globalCompositeOperation = "difference"; // ctx.fillRect(0, 0, canvas.width, canvas.height); + // ctx.globalCompositeOperation = "source-over"; // ctx.globalAlpha = (mech.health < 0.7) ? (mech.health+0.3)*(mech.health+0.3) : 1 // if (mech.health < 0.7) { @@ -393,11 +410,11 @@ const game = { b.guns[i].have = false; if (b.guns[i].ammo != Infinity) b.guns[i].ammo = 0; } + b.activeGun = null; game.paused = false; engine.timing.timeScale = 1; game.dmgScale = 1; b.dmgScale = 0.7; - b.activeGun = null; game.makeGunHUD(); mech.drop(); mech.addHealth(1); @@ -408,8 +425,7 @@ const game = { document.getElementById("text-log").style.opacity = 0; document.getElementById("fade-out").style.opacity = 0; document.title = "n-gon"; - // mech.fieldUpgrades[0](); //reset to starting field? or let them keep the field - if (!mech.fieldMode) mech.fieldUpgrades[0](); //reset to starting field? or let them keep the field + if (!mech.fieldMode) mech.fieldUpgrades[0].effect(); //reset to starting field? or let them keep the field }, firstRun: true, splashReturn() { diff --git a/js/index.js b/js/index.js index ae179bb..0923788 100644 --- a/js/index.js +++ b/js/index.js @@ -2,6 +2,9 @@ /* TODO: ******************************************* ***************************************************** +make player legs just slide if the player is above the normal speed + like when you fire the one shot + make power ups keep moving to player if the field is turned off levels spawn by having the map aspects randomly fly into place diff --git a/js/level.js b/js/level.js index 7b75d31..09c8a0a 100644 --- a/js/level.js +++ b/js/level.js @@ -12,11 +12,11 @@ const level = { onLevel: 0, start() { if (game.levelsCleared === 0) { - // game.levelsCleared = 5; //for testing to simulate possible mobs spawns + // game.levelsCleared = 6; //for testing to simulate possible mobs spawns // b.giveGuns("all", 1000) // b.giveGuns(3) // set a starting gun for testing - // mech.fieldUpgrades[2](); //give a field power up for testing - // b.mods[6].effect(); //give specific mod + // mech.fieldUpgrades[2].effect(); //give a field power up for testing + // b.mods[7].effect(); //give specific mod this.intro(); //starting level // this.testingMap(); @@ -28,11 +28,11 @@ const level = { // this.office(); } else { spawn.setSpawnList(); //picks a couple mobs types for a themed random mob spawns - this[this.levels[this.onLevel]](); //picks the current map from the the levels array - this.levelAnnounce(); + level[level.levels[level.onLevel]](); //picks the current map from the the levels array + level.levelAnnounce(); } game.setZoom(); - this.addToWorld(); //add bodies to game engine + level.addToWorld(); //add bodies to game engine game.draw.setPaths(); }, difficultyIncrease() { diff --git a/js/player.js b/js/player.js index 1ca8e98..0b2ddeb 100644 --- a/js/player.js +++ b/js/player.js @@ -358,7 +358,61 @@ const mech = { }, alive: true, death() { - if (this.alive) { + if (b.modIsImmortal) { //if player has the immortality buff, spawn on the same level with randomized stats + //remove mod + b.mod = null + b.setModDefaults(); + b.modText(); + + //randomize guns + b.activeGun = null; + b.inventory = []; //removes guns and ammo + for (let i = 0, len = b.guns.length; i < len; ++i) { + b.guns[i].have = false; + if (b.guns[i].ammo != Infinity) b.guns[i].ammo = 0; + } + if (game.levelsCleared > 0) powerUps.gun.effect(); + if (game.levelsCleared > 1) powerUps.gun.effect(); + if (game.levelsCleared > 3) powerUps.gun.effect(); + if (game.levelsCleared > 6) powerUps.gun.effect(); + game.makeGunHUD(); + + //randomize field + + if (game.levelsCleared > 5) { + mech.fieldUpgrades[Math.floor(Math.random() * (mech.fieldUpgrades.length))].effect(); + } else { + mech.fieldUpgrades[0].effect(); + } + + mech.addHealth(1); + spawn.setSpawnList(); + game.clearNow = true; + + game.wipe = function () { //set wipe to have trails + ctx.fillStyle = "rgba(255,255,255,0.01)"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + } + + for (let i = 0; i < 7; i++) { + setTimeout(function () { + game.makeTextLog(`
probability amplitude will synchronize in ${7-i} seconds
`, 1000); + game.wipe = function () { //set wipe to have trails + ctx.fillStyle = `rgba(255,255,255,${(i+1)*0.04})`; + ctx.fillRect(0, 0, canvas.width, canvas.height); + } + }, (i + 1) * 1000); + } + + setTimeout(function () { + game.wipe = function () { //set wipe to normal + ctx.clearRect(0, 0, canvas.width, canvas.height); + } + game.makeTextLog("
Quantum Immortality has stabilized your probability amplitude
welcome to your new reality
", 1000); + document.title = "n-gon: L" + (game.levelsCleared) + " " + level.levels[level.onLevel] + " version 2"; + }, 8000); + + } else if (this.alive) { //normal death code here this.alive = false; game.paused = true; this.health = 0; @@ -844,355 +898,387 @@ const mech = { } }, hold() {}, - fieldUpgrades: [ - () => { - mech.fieldMode = 0; - game.makeTextLog("Field Emitter
(right click or space bar)

lets you pick up and throw objects
shields you from damage

", 1200); - mech.setHoldDefaults(); - mech.hold = function () { - if (mech.isHolding) { - mech.drawHold(mech.holdingTarget); - mech.holding(); - mech.throw(); - } else if ((keys[32] || game.mouseDownRight && mech.fieldMeter > 0.1)) { //not hold but field button is pressed - mech.drawField(); - mech.grabPowerUp(); - mech.pushMobs(); - mech.lookForPickUp(); - } else if (mech.holdingTarget && mech.fireCDcycle < mech.cycle && mech.fieldMeter > 0.05) { //holding, but field button is released - mech.pickUp(); - } else { - mech.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists) + fieldText() { + game.makeTextLog(`${mech.fieldUpgrades[mech.fieldMode].name}
(right click or space bar)

${mech.fieldUpgrades[mech.fieldMode].description}

`, 1200); + game.updateModHUD() + }, + fieldUpgrades: [{ + name: "Field Emitter", + description: "lets you pick up and throw objects
shields you from damage", + effect: () => { + mech.fieldMode = 0; + mech.fieldText(); + // game.makeTextLog("
(right click or space bar)

", 1200); + mech.setHoldDefaults(); + mech.hold = function () { + if (mech.isHolding) { + mech.drawHold(mech.holdingTarget); + mech.holding(); + mech.throw(); + } else if ((keys[32] || game.mouseDownRight && mech.fieldMeter > 0.1)) { //not hold but field button is pressed + mech.drawField(); + mech.grabPowerUp(); + mech.pushMobs(); + mech.lookForPickUp(); + } else if (mech.holdingTarget && mech.fireCDcycle < mech.cycle && mech.fieldMeter > 0.05) { //holding, but field button is released + mech.pickUp(); + } else { + mech.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists) + } + mech.drawFieldMeter() } - mech.drawFieldMeter() } }, - () => { - mech.fieldMode = 1; - game.makeTextLog("Time Dilation Field
(right click or space bar)

stop time while field is active
can fire while field is active

", 1200); - mech.setHoldDefaults(); - mech.fieldFire = true; - mech.grabRange = 130 - mech.isBodiesAsleep = false; - mech.hold = function () { - if (mech.isHolding) { - mech.wakeCheck(); - mech.drawHold(mech.holdingTarget); - mech.holding(); - mech.throw(); - } else if ((keys[32] || game.mouseDownRight) && mech.fieldCDcycle < mech.cycle) { - const DRAIN = 0.0022 - if (mech.fieldMeter > DRAIN) { - mech.fieldMeter -= DRAIN; + { + name: "Time Dilation Field", + description: "stop time while field is active
can fire while field is active", + effect: () => { + mech.fieldMode = 1; + mech.fieldText(); + mech.setHoldDefaults(); + mech.fieldFire = true; + mech.grabRange = 130 + mech.isBodiesAsleep = false; + mech.hold = function () { + if (mech.isHolding) { + mech.wakeCheck(); + mech.drawHold(mech.holdingTarget); + mech.holding(); + mech.throw(); + } else if ((keys[32] || game.mouseDownRight) && mech.fieldCDcycle < mech.cycle) { + const DRAIN = 0.0027 + if (mech.fieldMeter > DRAIN) { + mech.fieldMeter -= DRAIN; - //draw field everywhere - ctx.fillStyle = "rgba(110,170,200," + (0.19 + 0.16 * Math.random()) + ")"; - ctx.fillRect(-100000, -100000, 200000, 200000) + //draw field everywhere + ctx.fillStyle = "rgba(110,170,200," + (0.19 + 0.16 * Math.random()) + ")"; + ctx.fillRect(-100000, -100000, 200000, 200000) - //stop time - mech.isBodiesAsleep = true; + //stop time + mech.isBodiesAsleep = true; - function sleep(who) { - for (let i = 0, len = who.length; i < len; ++i) { - if (!who[i].isSleeping) { - who[i].storeVelocity = who[i].velocity - who[i].storeAngularVelocity = who[i].angularVelocity + function sleep(who) { + for (let i = 0, len = who.length; i < len; ++i) { + if (!who[i].isSleeping) { + who[i].storeVelocity = who[i].velocity + who[i].storeAngularVelocity = who[i].angularVelocity + } + Matter.Sleeping.set(who[i], true) } - Matter.Sleeping.set(who[i], true) } - } - sleep(mob); - sleep(body); - sleep(bullet); - //doesn't really work, just slows down constraints - for (let i = 0, len = cons.length; i < len; i++) { - if (cons[i].stiffness !== 0) { - cons[i].storeStiffness = cons[i].stiffness; - cons[i].stiffness = 0; + sleep(mob); + sleep(body); + sleep(bullet); + //doesn't really work, just slows down constraints + for (let i = 0, len = cons.length; i < len; i++) { + if (cons[i].stiffness !== 0) { + cons[i].storeStiffness = cons[i].stiffness; + cons[i].stiffness = 0; + } } - } - game.cycle--; //pause all functions that depend on game cycle increasing + game.cycle--; //pause all functions that depend on game cycle increasing - mech.grabPowerUp(); - mech.lookForPickUp(180); + mech.grabPowerUp(); + mech.lookForPickUp(180); + } else { + mech.wakeCheck(); + mech.fieldCDcycle = mech.cycle + 120; + } + } else if (mech.holdingTarget && mech.fireCDcycle < mech.cycle && mech.fieldMeter > 0.05) { //holding, but field button is released + mech.wakeCheck(); + mech.pickUp(); } else { mech.wakeCheck(); - mech.fieldCDcycle = mech.cycle + 120; + mech.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists) } - } else if (mech.holdingTarget && mech.fireCDcycle < mech.cycle && mech.fieldMeter > 0.05) { //holding, but field button is released - mech.wakeCheck(); - mech.pickUp(); - } else { - mech.wakeCheck(); - mech.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists) - } - mech.drawFieldMeter() - if (mech.fieldMode !== 1) { - //wake up if this is no longer the current field mode, like after a new power up - mech.wakeCheck(); + mech.drawFieldMeter() + if (mech.fieldMode !== 1) { + //wake up if this is no longer the current field mode, like after a new power up + mech.wakeCheck(); + } } } }, - () => { - mech.fieldMode = 2; - game.makeTextLog("Electrostatic Force Field
(right click or space bar)

field does damage on contact
blocks are thrown at a higher velocity
increased field regeneration

", 1200); - mech.setHoldDefaults(); - //throw quicker and harder - mech.grabRange = 225; - mech.fieldShieldingScale = 2; - mech.fieldRegen *= 3; - mech.throwChargeRate = 3; - mech.throwChargeMax = 140; - mech.fieldDamage = 5; //passive field does extra damage - // mech.fieldArc = 0.11 - // mech.calculateFieldThreshold(); //run after setting fieldArc, used for powerUp grab and mobPush with lookingAt(mob) + { + name: "Electrostatic Force Field", + description: "field does damage on contact
blocks are thrown at a higher velocity
increased field regeneration", + effect: () => { + mech.fieldMode = 2; + mech.fieldText(); + mech.setHoldDefaults(); + //throw quicker and harder + mech.grabRange = 225; + mech.fieldShieldingScale = 2; + mech.fieldRegen *= 3; + mech.throwChargeRate = 3; + mech.throwChargeMax = 140; + mech.fieldDamage = 5; //passive field does extra damage + // mech.fieldArc = 0.11 + // mech.calculateFieldThreshold(); //run after setting fieldArc, used for powerUp grab and mobPush with lookingAt(mob) - mech.hold = function () { - if (mech.isHolding) { - mech.drawHold(mech.holdingTarget); - mech.holding(); - mech.throw(); - } else if ((keys[32] || game.mouseDownRight) && mech.fieldMeter > 0.15) { //not hold but field button is pressed - //draw electricity - const Dx = Math.cos(mech.angle); - const Dy = Math.sin(mech.angle); - let x = mech.pos.x + 20 * Dx; - let y = mech.pos.y + 20 * Dy; - ctx.beginPath(); - ctx.moveTo(x, y); - for (let i = 0; i < 8; i++) { - x += 18 * (Dx + 2 * (Math.random() - 0.5)) - y += 18 * (Dy + 2 * (Math.random() - 0.5)) - ctx.lineTo(x, y); - } - ctx.lineWidth = 1 //0.5 + 2 * Math.random(); - ctx.strokeStyle = `rgba(100,20,50,${0.5+0.5*Math.random()})`; - ctx.stroke(); - - //draw field - const range = 170; - const arc = Math.PI * 0.11 - ctx.beginPath(); - ctx.arc(mech.pos.x, mech.pos.y, range, mech.angle - arc, mech.angle + arc, false); - ctx.lineTo(mech.pos.x + 13 * Math.cos(mech.angle), mech.pos.y + 13 * Math.sin(mech.angle)); - if (mech.holdingTarget) { - ctx.fillStyle = "rgba(255,50,150," + (0.05 + 0.1 * Math.random()) + ")"; - } else { - ctx.fillStyle = "rgba(255,50,150," + (0.13 + 0.18 * Math.random()) + ")"; - } - ctx.fill(); - - //draw random lines in field for cool effect - // eye = 15; - // ctx.beginPath(); - // ctx.moveTo(mech.pos.x + eye * Math.cos(mech.angle), mech.pos.y + eye * Math.sin(mech.angle)); - // const offAngle = mech.angle + 2 * Math.PI * mech.fieldArc * (Math.random() - 0.5); - // ctx.lineTo(mech.pos.x + range * Math.cos(offAngle), mech.pos.y + range * Math.sin(offAngle)); - // ctx.strokeStyle = "rgba(100,20,50,0.2)"; - // ctx.stroke(); - - mech.grabPowerUp(); - mech.pushMobs(); - mech.lookForPickUp(); - } else if (mech.holdingTarget && mech.fireCDcycle < mech.cycle && mech.fieldMeter > 0.05) { //holding, but field button is released - mech.pickUp(); - } else { - mech.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists) - } - mech.drawFieldMeter() - } - }, - () => { - mech.fieldMode = 3; - game.makeTextLog("Negative Mass Field
(right click or space bar)

field nullifies gravity
player can hold more massive objects
can fire while field is active

", 1200); - //
decreased field shielding efficiency - mech.setHoldDefaults(); - mech.fieldFire = true; - mech.holdingMassScale = 0.05; //can hold heavier blocks with lower cost to jumping - mech.fieldShieldingScale = 2; - - mech.hold = function () { - if (mech.isHolding) { - mech.drawHold(mech.holdingTarget); - mech.holding(); - mech.throw(); - } else if ((keys[32] || game.mouseDownRight) && mech.fieldCDcycle < mech.cycle) { //push away - const DRAIN = 0.0007 - if (mech.fieldMeter > DRAIN) { - mech.pushMobs360(170); - mech.grabPowerUp(); - mech.lookForPickUp(170); - //look for nearby objects to make zero-g - function zeroG(who) { - for (let i = 0, len = who.length; i < len; ++i) { - sub = Matter.Vector.sub(who[i].position, mech.pos); - dist = Matter.Vector.magnitude(sub); - if (dist < mech.grabRange) { - who[i].force.y -= who[i].mass * (game.g * 1.06); //add a bit more then standard gravity - } - } - } - zeroG(powerUp); - zeroG(body); - // zeroG(bullet); //works fine, but not that noticeable and maybe not worth the possible performance hit - // zeroG(mob); //mobs are too irregular to make this work? - - Matter.Body.setVelocity(player, { - x: player.velocity.x, - y: player.velocity.y * 0.97 - }); - - if (keys[83] || keys[40]) { //down - player.force.y -= 0.8 * player.mass * mech.gravity; - mech.grabRange = mech.grabRange * 0.97 + 400 * 0.03; - } else if (keys[87] || keys[38]) { //up - mech.fieldMeter -= 3 * DRAIN; - mech.grabRange = mech.grabRange * 0.97 + 750 * 0.03; - player.force.y -= 1.2 * player.mass * mech.gravity; - } else { - mech.fieldMeter -= DRAIN; - mech.grabRange = mech.grabRange * 0.97 + 650 * 0.03; - player.force.y -= 1.07 * player.mass * mech.gravity; // slow upward drift - } - - //add extra friction for horizontal motion - if (keys[65] || keys[68] || keys[37] || keys[39]) { - Matter.Body.setVelocity(player, { - x: player.velocity.x * 0.85, - y: player.velocity.y - }); - } - - //draw zero-G range + mech.hold = function () { + if (mech.isHolding) { + mech.drawHold(mech.holdingTarget); + mech.holding(); + mech.throw(); + } else if ((keys[32] || game.mouseDownRight) && mech.fieldMeter > 0.15) { //not hold but field button is pressed + //draw electricity + const Dx = Math.cos(mech.angle); + const Dy = Math.sin(mech.angle); + let x = mech.pos.x + 20 * Dx; + let y = mech.pos.y + 20 * Dy; ctx.beginPath(); - ctx.arc(mech.pos.x, mech.pos.y, mech.grabRange, 0, 2 * Math.PI); - ctx.fillStyle = "#f5f5ff"; - ctx.globalCompositeOperation = "difference"; - ctx.fill(); - ctx.globalCompositeOperation = "source-over"; - } else { - //trigger cool down - mech.fieldCDcycle = mech.cycle + 120; - } - } else if (mech.holdingTarget && mech.fireCDcycle < mech.cycle && mech.fieldMeter > 0.05) { //holding, but field button is released - mech.pickUp(); - mech.grabRange = 0 - } else { - mech.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists) - mech.grabRange = 0 - } - mech.drawFieldMeter() - } - }, - () => { - mech.fieldMode = 4; - game.makeTextLog("Standing Wave Harmonics
(right click or space bar)

oscillating shields always surround player
decreased field regeneration

", 1200); - mech.setHoldDefaults(); - // mech.fieldShieldingScale = 0.5; - mech.fieldRegen *= 0.2; - - mech.hold = function () { - if (mech.isHolding) { - mech.drawHold(mech.holdingTarget); - mech.holding(); - mech.throw(); - } else if ((keys[32] || game.mouseDownRight && mech.fieldMeter > 0.1)) { //not hold but field button is pressed - mech.grabPowerUp(); - mech.lookForPickUp(180); - } else if (mech.holdingTarget && mech.fireCDcycle < mech.cycle) { //holding, but field button is released - mech.pickUp(); - } else { - mech.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists) - } - if (mech.fieldMeter > 0.1) { - const grabRange1 = 85 + 60 * Math.sin(mech.cycle / 23) - const grabRange2 = 80 + 70 * Math.sin(mech.cycle / 37) - const grabRange3 = 70 + 70 * Math.sin(mech.cycle / 47) - const netGrabRange = Math.max(grabRange1, grabRange2, grabRange3) - ctx.fillStyle = "rgba(110,170,200," + (0.15 + 0.15 * Math.random()) + ")"; - ctx.beginPath(); - ctx.arc(mech.pos.x, mech.pos.y, grabRange1, 0, 2 * Math.PI); - ctx.fill(); - ctx.beginPath(); - ctx.arc(mech.pos.x, mech.pos.y, grabRange2, 0, 2 * Math.PI); - ctx.fill(); - ctx.beginPath(); - ctx.arc(mech.pos.x, mech.pos.y, grabRange3, 0, 2 * Math.PI); - ctx.fill(); - mech.pushMobs360(netGrabRange); - } - mech.drawFieldMeter() - } - }, - () => { - mech.fieldMode = 5; - game.makeTextLog("Nano-Scale Manufacturing
(passive effect)

excess field energy used to build drones
increased field regeneration

", 1200); - mech.setHoldDefaults(); - mech.fieldRegen *= 3; - mech.hold = function () { - if (mech.fieldMeter === 1) { - mech.fieldMeter -= 0.5; - b.guns[12].fire() //spawn drone - } - if (mech.isHolding) { - mech.drawHold(mech.holdingTarget); - mech.holding(); - mech.throw(); - } else if ((keys[32] || game.mouseDownRight && mech.fieldMeter > 0.1)) { //not hold but field button is pressed - mech.pushMobs(); - mech.drawField(); - mech.grabPowerUp(); - mech.lookForPickUp(); - } else if (mech.holdingTarget && mech.fireCDcycle < mech.cycle && mech.fieldMeter > 0.05) { //holding, but field button is released - mech.pickUp(); - } else { - mech.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists) - } - mech.drawFieldMeter() - } - }, - () => { - mech.fieldMode = 6; - game.makeTextLog("Phase Decoherence Field
(right click or space bar)

intangible while field is active
can't see or be seen outside field

", 1200); - mech.setHoldDefaults(); - // mech.grabRange = 230 - mech.hold = function () { - mech.isStealth = false //isStealth is checked in mob foundPlayer() - player.collisionFilter.mask = 0x010011 //0x010011 is normal - if (mech.isHolding) { - mech.drawHold(mech.holdingTarget); - mech.holding(); - mech.throw(); - } else if ((keys[32] || game.mouseDownRight) && mech.fieldCDcycle < mech.cycle) { - const DRAIN = 0.002 - if (mech.fieldMeter > DRAIN) { - mech.fieldMeter -= DRAIN; - - mech.isStealth = true //isStealth is checked in mob foundPlayer() - player.collisionFilter.mask = 0x000001 //0x010011 is normals - - ctx.beginPath(); - ctx.arc(mech.pos.x, mech.pos.y, mech.grabRange, 0, 2 * Math.PI); - ctx.globalCompositeOperation = "destination-in"; //in or atop - ctx.fillStyle = "rgba(255,255,255,0.25)"; - ctx.fill(); - ctx.globalCompositeOperation = "source-over"; - ctx.strokeStyle = "#000" - ctx.lineWidth = 2; + ctx.moveTo(x, y); + for (let i = 0; i < 8; i++) { + x += 18 * (Dx + 2 * (Math.random() - 0.5)) + y += 18 * (Dy + 2 * (Math.random() - 0.5)) + ctx.lineTo(x, y); + } + ctx.lineWidth = 1 //0.5 + 2 * Math.random(); + ctx.strokeStyle = `rgba(100,20,50,${0.5+0.5*Math.random()})`; ctx.stroke(); + //draw field + const range = 170; + const arc = Math.PI * 0.11 + ctx.beginPath(); + ctx.arc(mech.pos.x, mech.pos.y, range, mech.angle - arc, mech.angle + arc, false); + ctx.lineTo(mech.pos.x + 13 * Math.cos(mech.angle), mech.pos.y + 13 * Math.sin(mech.angle)); + if (mech.holdingTarget) { + ctx.fillStyle = "rgba(255,50,150," + (0.05 + 0.1 * Math.random()) + ")"; + } else { + ctx.fillStyle = "rgba(255,50,150," + (0.13 + 0.18 * Math.random()) + ")"; + } + ctx.fill(); + + //draw random lines in field for cool effect + // eye = 15; + // ctx.beginPath(); + // ctx.moveTo(mech.pos.x + eye * Math.cos(mech.angle), mech.pos.y + eye * Math.sin(mech.angle)); + // const offAngle = mech.angle + 2 * Math.PI * mech.fieldArc * (Math.random() - 0.5); + // ctx.lineTo(mech.pos.x + range * Math.cos(offAngle), mech.pos.y + range * Math.sin(offAngle)); + // ctx.strokeStyle = "rgba(100,20,50,0.2)"; + // ctx.stroke(); + mech.grabPowerUp(); - mech.lookForPickUp(110); + mech.pushMobs(); + mech.lookForPickUp(); + } else if (mech.holdingTarget && mech.fireCDcycle < mech.cycle && mech.fieldMeter > 0.05) { //holding, but field button is released + mech.pickUp(); } else { - mech.fieldCDcycle = mech.cycle + 120; + mech.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists) } - } else if (mech.holdingTarget && mech.fireCDcycle < mech.cycle && mech.fieldMeter > 0.05) { //holding, but field button is released - mech.pickUp(); - } else { - mech.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists) + mech.drawFieldMeter() + } + } + }, + { + name: "Negative Mass Field", + description: "field nullifies gravity
player can hold more massive objects
can fire while field is active", + effect: () => { + mech.fieldMode = 3; + mech.fieldText(); + //
decreased field shielding efficiency + mech.setHoldDefaults(); + mech.fieldFire = true; + mech.holdingMassScale = 0.05; //can hold heavier blocks with lower cost to jumping + mech.fieldShieldingScale = 2; + + mech.hold = function () { + if (mech.isHolding) { + mech.drawHold(mech.holdingTarget); + mech.holding(); + mech.throw(); + } else if ((keys[32] || game.mouseDownRight) && mech.fieldCDcycle < mech.cycle) { //push away + const DRAIN = 0.0006 + if (mech.fieldMeter > DRAIN) { + mech.pushMobs360(170); + mech.grabPowerUp(); + mech.lookForPickUp(170); + //look for nearby objects to make zero-g + function zeroG(who) { + for (let i = 0, len = who.length; i < len; ++i) { + sub = Matter.Vector.sub(who[i].position, mech.pos); + dist = Matter.Vector.magnitude(sub); + if (dist < mech.grabRange) { + who[i].force.y -= who[i].mass * (game.g * 1.06); //add a bit more then standard gravity + } + } + } + zeroG(powerUp); + zeroG(body); + // zeroG(bullet); //works fine, but not that noticeable and maybe not worth the possible performance hit + // zeroG(mob); //mobs are too irregular to make this work? + + Matter.Body.setVelocity(player, { + x: player.velocity.x, + y: player.velocity.y * 0.97 + }); + + if (keys[83] || keys[40]) { //down + player.force.y -= 0.8 * player.mass * mech.gravity; + mech.grabRange = mech.grabRange * 0.97 + 400 * 0.03; + } else if (keys[87] || keys[38]) { //up + mech.fieldMeter -= 3 * DRAIN; + mech.grabRange = mech.grabRange * 0.97 + 750 * 0.03; + player.force.y -= 1.2 * player.mass * mech.gravity; + } else { + mech.fieldMeter -= DRAIN; + mech.grabRange = mech.grabRange * 0.97 + 650 * 0.03; + player.force.y -= 1.07 * player.mass * mech.gravity; // slow upward drift + } + + //add extra friction for horizontal motion + if (keys[65] || keys[68] || keys[37] || keys[39]) { + Matter.Body.setVelocity(player, { + x: player.velocity.x * 0.85, + y: player.velocity.y + }); + } + + //draw zero-G range + ctx.beginPath(); + ctx.arc(mech.pos.x, mech.pos.y, mech.grabRange, 0, 2 * Math.PI); + ctx.fillStyle = "#f5f5ff"; + ctx.globalCompositeOperation = "difference"; + ctx.fill(); + ctx.globalCompositeOperation = "source-over"; + } else { + //trigger cool down + mech.fieldCDcycle = mech.cycle + 120; + } + } else if (mech.holdingTarget && mech.fireCDcycle < mech.cycle && mech.fieldMeter > 0.05) { //holding, but field button is released + mech.pickUp(); + mech.grabRange = 0 + } else { + mech.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists) + mech.grabRange = 0 + } + mech.drawFieldMeter() + } + } + }, + { + name: "Standing Wave Harmonics", + description: "oscillating shields always surround player
decreased field regeneration", + effect: () => { + mech.fieldMode = 4; + mech.fieldText(); + mech.setHoldDefaults(); + // mech.fieldShieldingScale = 0.5; + mech.fieldRegen *= 0.2; + + mech.hold = function () { + if (mech.isHolding) { + mech.drawHold(mech.holdingTarget); + mech.holding(); + mech.throw(); + } else if ((keys[32] || game.mouseDownRight && mech.fieldMeter > 0.1)) { //not hold but field button is pressed + mech.grabPowerUp(); + mech.lookForPickUp(180); + } else if (mech.holdingTarget && mech.fireCDcycle < mech.cycle) { //holding, but field button is released + mech.pickUp(); + } else { + mech.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists) + } + if (mech.fieldMeter > 0.1) { + const grabRange1 = 90 + 60 * Math.sin(mech.cycle / 23) + const grabRange2 = 85 + 70 * Math.sin(mech.cycle / 37) + const grabRange3 = 80 + 80 * Math.sin(mech.cycle / 47) + const netGrabRange = Math.max(grabRange1, grabRange2, grabRange3) + ctx.fillStyle = "rgba(110,170,200," + (0.15 + 0.15 * Math.random()) + ")"; + ctx.beginPath(); + ctx.arc(mech.pos.x, mech.pos.y, grabRange1, 0, 2 * Math.PI); + ctx.fill(); + ctx.beginPath(); + ctx.arc(mech.pos.x, mech.pos.y, grabRange2, 0, 2 * Math.PI); + ctx.fill(); + ctx.beginPath(); + ctx.arc(mech.pos.x, mech.pos.y, grabRange3, 0, 2 * Math.PI); + ctx.fill(); + mech.pushMobs360(netGrabRange); + } + mech.drawFieldMeter() + } + } + }, + { + name: "Nano-Scale Manufacturing", + description: "excess field energy used to build drones
increased field regeneration", + effect: () => { + mech.fieldMode = 5; + mech.fieldText(); + mech.setHoldDefaults(); + mech.fieldRegen *= 3.5; + mech.hold = function () { + if (mech.fieldMeter === 1) { + mech.fieldMeter -= 0.5; + b.guns[12].fire() //spawn drone + } + if (mech.isHolding) { + mech.drawHold(mech.holdingTarget); + mech.holding(); + mech.throw(); + } else if ((keys[32] || game.mouseDownRight && mech.fieldMeter > 0.1)) { //not hold but field button is pressed + mech.pushMobs(); + mech.drawField(); + mech.grabPowerUp(); + mech.lookForPickUp(); + } else if (mech.holdingTarget && mech.fireCDcycle < mech.cycle && mech.fieldMeter > 0.05) { //holding, but field button is released + mech.pickUp(); + } else { + mech.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists) + } + mech.drawFieldMeter() + } + } + }, + { + name: "Phase Decoherence Field", + description: "intangible while field is active
can't see or be seen outside field", + effect: () => { + mech.fieldMode = 6; + mech.fieldText(); + mech.setHoldDefaults(); + // mech.grabRange = 230 + mech.hold = function () { + mech.isStealth = false //isStealth is checked in mob foundPlayer() + player.collisionFilter.mask = 0x010011 //0x010011 is normal + if (mech.isHolding) { + mech.drawHold(mech.holdingTarget); + mech.holding(); + mech.throw(); + } else if ((keys[32] || game.mouseDownRight) && mech.fieldCDcycle < mech.cycle) { + const DRAIN = 0.002 + if (mech.fieldMeter > DRAIN) { + mech.fieldMeter -= DRAIN; + + mech.isStealth = true //isStealth is checked in mob foundPlayer() + player.collisionFilter.mask = 0x000001 //0x010011 is normals + + ctx.beginPath(); + ctx.arc(mech.pos.x, mech.pos.y, mech.grabRange, 0, 2 * Math.PI); + ctx.globalCompositeOperation = "destination-in"; //in or atop + ctx.fillStyle = "rgba(255,255,255,0.25)"; + ctx.fill(); + ctx.globalCompositeOperation = "source-over"; + ctx.strokeStyle = "#000" + ctx.lineWidth = 2; + ctx.stroke(); + + mech.grabPowerUp(); + mech.lookForPickUp(110); + } else { + mech.fieldCDcycle = mech.cycle + 120; + } + } else if (mech.holdingTarget && mech.fireCDcycle < mech.cycle && mech.fieldMeter > 0.05) { //holding, but field button is released + mech.pickUp(); + } else { + mech.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists) + } + mech.drawFieldMeter() } - mech.drawFieldMeter() } }, // () => { diff --git a/js/powerups.js b/js/powerups.js index 84108d6..b43db1a 100644 --- a/js/powerups.js +++ b/js/powerups.js @@ -28,9 +28,9 @@ const powerUps = { while (mode === mech.fieldMode) { mode = Math.ceil(Math.random() * (mech.fieldUpgrades.length - 1)) } - mech.fieldUpgrades[mode](); //choose random field upgrade that you don't already have + mech.fieldUpgrades[mode].effect(); //choose random field upgrade that you don't already have } else { - mech.fieldUpgrades[this.mode](); //set a predetermined power up + mech.fieldUpgrades[this.mode].effect(); //set a predetermined power up } //pop the old field out in case player wants to swap back if (previousMode !== 0) { diff --git a/js/spawn.js b/js/spawn.js index aa89bec..6ab1a6e 100644 --- a/js/spawn.js +++ b/js/spawn.js @@ -491,12 +491,12 @@ const spawn = { me.onDeath = function () { //applying forces to player doesn't seem to work inside this method, not sure why powerUps.spawnBossPowerUp(this.position.x, this.position.y) - if (game.levelsCleared > 6) { - for (let i = 0; i < (game.levelsCleared - 5); ++i) { - spawn.sucker(this.position.x + (Math.random() - 0.5) * radius * 2, this.position.y + (Math.random() - 0.5) * radius * 2, 20); + if (game.levelsCleared > 5) { + for (let i = 0; i < (game.levelsCleared - 3); ++i) { + spawn.sucker(this.position.x + (Math.random() - 0.5) * radius * 2, this.position.y + (Math.random() - 0.5) * radius * 2, 70 * Math.random()); Matter.Body.setVelocity(mob[mob.length - 1], { - x: (Math.random() - 0.5) * 25, - y: (Math.random() - 0.5) * 25 + x: (Math.random() - 0.5) * 70, + y: (Math.random() - 0.5) * 70 }); } } @@ -540,7 +540,7 @@ const spawn = { ctx.fill(); ctx.beginPath(); ctx.arc(this.position.x, this.position.y, eventHorizon, 0, 2 * Math.PI); - ctx.fillStyle = "rgba(0,20,40,0.05)"; + ctx.fillStyle = "rgba(0,0,0,0.05)"; ctx.fill(); //when player is inside event horizon if (Matter.Vector.magnitude(Matter.Vector.sub(this.position, player.position)) < eventHorizon) { diff --git a/style.css b/style.css index 32cdab1..a2fed17 100644 --- a/style.css +++ b/style.css @@ -68,8 +68,8 @@ summary { #health-bg { position: absolute; - top: 30px; - left: 40px; + top: 15px; + left: 15px; height: 20px; width: 300px; background-color: #000; @@ -81,8 +81,8 @@ summary { #health { position: absolute; - top: 30px; - left: 40px; + top: 15px; + left: 15px; height: 20px; width: 0px; transition: width 1s ease-out; @@ -119,10 +119,10 @@ summary { #guns { position: absolute; - top: 55px; - left: 40px; + top: 40px; + left: 15px; z-index: 2; - font-size: 25px; + font-size: 23px; color: #111; background-color: rgba(255, 255, 255, 0.4); user-select: none; @@ -134,12 +134,14 @@ summary { #mods { position: absolute; - top: 20px; - right: 20px; + top: 15px; + right: 15px; z-index: 2; - font-size: 21px; - color: #111; + font-size: 19px; + color: #000; + text-align: right; opacity: 0.5; + line-height: 140%; background-color: rgba(255, 255, 255, 0.4); user-select: none; pointer-events: none;