From 57126ab42ea2a1bfc610c9953a144a89c3948e95 Mon Sep 17 00:00:00 2001 From: landgreen Date: Sat, 18 Jan 2020 07:51:03 -0800 Subject: [PATCH] custom run difficulty scaling --- js/bullets.js | 86 +++++++++++--------------- js/engine.js | 79 ++++++++++++------------ js/game.js | 2 +- js/index.js | 159 ++++++++++++++++++++++++++++++------------------- js/level.js | 2 +- js/player.js | 2 +- js/powerups.js | 13 ++-- style.css | 4 ++ 8 files changed, 185 insertions(+), 162 deletions(-) diff --git a/js/bullets.js b/js/bullets.js index 6a1a19f..5b563b4 100644 --- a/js/bullets.js +++ b/js/bullets.js @@ -72,20 +72,20 @@ const b = { }, mods: [{ name: "depleted uranium rounds", //0 - description: `your bullets are +11% larger
increased mass and physical damage`, + description: `your bullets are +13% larger
increased mass and physical damage`, count: 0, - maxCount: 4, + maxCount: 33, effect() { - b.modBulletSize += 0.11 + b.modBulletSize += 0.13 } }, { name: "fluoroantimonic acid", //1 description: "each bullet does extra chemical damage
instant damage, unaffected by momentum", - maxCount: 4, + maxCount: 9, count: 0, effect() { - b.modExtraDmg += 0.25 + b.modExtraDmg += 0.3 game.playerDmgColor = "rgba(0,80,80,0.9)" } }, @@ -105,22 +105,6 @@ const b = { count: 0, effect() { b.isModFarAwayDmg = true; //used in mob.damage() - // game.drawList.push({ //draw range - // //add dmg to draw queue - // x: player.position.x, - // y: player.position.y, - // radius: 3000, - // color: "rgba(255,0,0,0.05)", - // time: 120 - // }); - // game.drawList.push({ //draw range - // //add dmg to draw queue - // x: player.position.x, - // y: player.position.y, - // radius: 500, - // color: "rgba(0,0,0,0.2)", - // time: 120 - // }); } }, { @@ -135,7 +119,7 @@ const b = { { name: "high explosives", //15 description: "the radius of explosions are +20% larger
immune to harm from explosions", - maxCount: 4, + maxCount: 1, count: 0, effect: () => { b.modExplosionRadius += 0.2; @@ -145,7 +129,7 @@ const b = { { name: "auto-loading heuristics", //5 description: "your delay after firing is +12% shorter", - maxCount: 4, + maxCount: 9, count: 0, effect() { b.modFireRate *= 0.88 @@ -163,7 +147,7 @@ const b = { { name: "Lorentzian topology", //7 description: "your bullets last +33% longer", - maxCount: 4, + maxCount: 9, count: 0, effect() { b.isModBulletsLastLonger += 0.33 @@ -172,7 +156,7 @@ const b = { { name: "zoospore vector", //8 description: "enemies discharge spores on death
+11% chance", - maxCount: 4, + maxCount: 9, count: 0, effect() { b.modSpores += 0.11; @@ -184,7 +168,7 @@ const b = { { name: "laser-bot", //10 description: "a bot defends the space around you
uses a short range laser that drains energy", - maxCount: 4, + maxCount: 9, count: 0, effect() { b.modLaserBotCount++; @@ -194,7 +178,7 @@ const b = { { name: "nail-bot", //11 description: "a bot fires nails at targets in line of sight", - maxCount: 4, + maxCount: 9, count: 0, effect() { b.modNailBotCount++; @@ -216,7 +200,7 @@ const b = { { name: "bremsstrahlung radiation", //13 description: "when your field blocks it also does damage", - maxCount: 4, + maxCount: 9, count: 0, effect() { b.modBlockDmg += 0.7 //if you change this value also update the for loop in the electricity graphics in mech.pushMass @@ -244,11 +228,11 @@ const b = { }, { name: "Pauli exclusion", //12 - description: "unable to collide with enemies for +2 seconds
activates after being harmed from a collision", - maxCount: 1, + description: "unable to collide with enemies for +1 second
activates after being harmed from a collision", + maxCount: 9, count: 0, effect() { - b.modCollisionImmuneCycles += 120; + b.modCollisionImmuneCycles += 60; mech.collisionImmune = mech.cycle + b.modCollisionImmuneCycles; //player is immune to collision damage for 30 cycles } }, @@ -274,7 +258,7 @@ const b = { { name: "energy conservation", //18 description: "gain energy proportional to damage done", - maxCount: 4, + maxCount: 9, count: 0, effect() { b.modEnergySiphon += 0.15; @@ -284,7 +268,7 @@ const b = { { name: "entropy exchange", //19 description: "heal proportional to damage done", - maxCount: 4, + maxCount: 9, count: 0, effect() { b.modHealthDrain += 0.015; @@ -293,7 +277,7 @@ const b = { { name: "overcharge", //20 description: "charge energy +33% beyond your maximum", - maxCount: 4, + maxCount: 9, count: 0, effect() { mech.fieldEnergyMax += 0.33 @@ -303,7 +287,7 @@ const b = { { name: "supersaturation", //21 description: "heal +33% beyond your max health", - maxCount: 4, + maxCount: 9, count: 0, effect() { mech.maxHealth += 0.33 @@ -313,7 +297,7 @@ const b = { { name: "recursive healing", //22 description: "healing power ups trigger an extra time.", - maxCount: 4, + maxCount: 9, count: 0, effect() { b.modRecursiveHealing += 1 @@ -321,7 +305,7 @@ const b = { }, { name: "mass-energy equivalence", //23 - description: "convert the mass of power ups into energy
power ups fill your energy and heal for +5%", + description: "power ups fill your energy and heal for +5%", maxCount: 1, count: 0, effect: () => { @@ -338,15 +322,6 @@ const b = { b.isModImmortal = true; } }, - { - name: "+1 cardinality", //24 - description: "one extra choice when selecting power ups", - maxCount: 1, - count: 0, - effect: () => { - b.isModFourOptions = true; - } - }, { name: "Bayesian inference", //25 description: "20% chance for double power ups to drop
one fewer choice when selecting power ups", @@ -356,6 +331,15 @@ const b = { b.isModBayesian = 0.20; } }, + { + name: "+1 cardinality", //24 + description: "one extra choice when selecting power ups", + maxCount: 1, + count: 0, + effect: () => { + b.isModFourOptions = true; + } + }, { name: "Born rule", //26 description: "remove all current mods
spawn new mods to replace them", @@ -1059,7 +1043,7 @@ const b = { Matter.Query.ray(body, this.position, mob[i].position).length === 0) { target = Vector.add(mob[i].position, Vector.mult(mob[i].velocity, Math.sqrt(dist) / 60)) const SPEED = 50 - b.nail(this.position, Vector.mult(Vector.normalise(Vector.sub(target, this.position)), SPEED), 0.3) + b.nail(this.position, Vector.mult(Vector.normalise(Vector.sub(target, this.position)), SPEED), 0.4) break; } } @@ -1294,10 +1278,10 @@ const b = { have: false, isStarterGun: true, fire() { - mech.fireCDcycle = mech.cycle + Math.floor((mech.crouch ? 35 : 20) * b.modFireRate); // cool down + mech.fireCDcycle = mech.cycle + Math.floor((mech.crouch ? 30 : 20) * b.modFireRate); // cool down b.muzzleFlash(20); // mobs.alert(450); - const SPEED = mech.crouch ? 55 : 35 + const SPEED = mech.crouch ? 45 : 35 const SPREAD = mech.crouch ? 0.04 : 0.15 let dir = mech.angle - SPREAD * 2; for (let i = 0; i < 5; i++) { @@ -1368,7 +1352,7 @@ const b = { fire() { const me = bullet.length; const dir = mech.angle - const SCALE = (mech.crouch ? 0.963 : 0.95) + const SCALE = (mech.crouch ? 0.963 : 0.95) + 0.03 * Math.min(1, 0.5 * (b.isModBulletsLastLonger - 1)) const wiggleMag = ((mech.crouch) ? 0.004 : 0.005) * ((mech.flipLegs === 1) ? 1 : -1) bullet[me] = Bodies.polygon(mech.pos.x + 25 * Math.cos(dir), mech.pos.y + 25 * Math.sin(dir), 10, 10 * b.modBulletSize, { angle: dir, @@ -1623,10 +1607,10 @@ const b = { fireCycle: 0, ammoLoaded: 0, fire() { - const thrust = 0.0005; let dir = mech.angle + (0.5 - Math.random()) * (mech.crouch ? 0 : 0.2); const me = bullet.length; bullet[me] = Bodies.rectangle(mech.pos.x + 40 * Math.cos(mech.angle), mech.pos.y + 40 * Math.sin(mech.angle) - 3, 30 * b.modBulletSize, 4 * b.modBulletSize, b.fireAttributes(dir)); + const thrust = 0.00417 * bullet[me].mass; b.fireProps(mech.crouch ? 55 : 30, -3 * (0.5 - Math.random()) + (mech.crouch ? 25 : -8), dir, me); //cd , speed // bullet[me].collisionFilter.mask = cat.map | cat.body | cat.mobBullet // Matter.Body.setDensity(bullet[me], 0.01) //doesn't help with reducing explosion knock backs diff --git a/js/engine.js b/js/engine.js index 008aff5..527af55 100644 --- a/js/engine.js +++ b/js/engine.js @@ -102,7 +102,8 @@ function collisionChecks(event) { function collidePlayer(obj, speedThreshold = 12, massThreshold = 2) { if (obj.classType === "body" && obj.speed > speedThreshold && obj.mass > massThreshold) { //dmg from hitting a body const v = Vector.magnitude(Vector.sub(player.velocity, obj.velocity)); - if (v > speedThreshold) { + if (v > speedThreshold && mech.collisionImmune < mech.cycle) { + mech.collisionImmune = mech.cycle + b.modCollisionImmuneCycles; //player is immune to collision damage for 30 cycles let dmg = Math.sqrt((v - speedThreshold + 0.1) * (obj.mass - massThreshold)) * 0.01; dmg = Math.min(Math.max(dmg, 0.02), 0.15); mech.damage(dmg); @@ -131,47 +132,45 @@ function collisionChecks(event) { function collideMob(obj) { //player + mob collision - if (mech.collisionImmune < mech.cycle) { - if (obj === playerBody || obj === playerHead) { - mech.collisionImmune = mech.cycle + b.modCollisionImmuneCycles; //player is immune to collision damage for 30 cycles - mob[k].foundPlayer(); - let dmg = Math.min(Math.max(0.025 * Math.sqrt(mob[k].mass), 0.05), 0.3) * game.dmgScale; //player damage is capped at 0.3*dmgScale of 1.0 - mech.damage(dmg); - if (mob[k].onHit) mob[k].onHit(k); - if (b.isModPiezo) mech.fieldMeter = mech.fieldEnergyMax; - if (b.isModAnnihilation && mob[k].dropPowerUp && !mob[k].isShielded) { - mob[k].death(); - game.drawList.push({ - //add dmg to draw queue - x: pairs[i].activeContacts[0].vertex.x, - y: pairs[i].activeContacts[0].vertex.y, - radius: dmg * 2000, - color: "rgba(255,0,255,0.2)", - time: game.drawTime - }); - } else { - game.drawList.push({ - //add dmg to draw queue - x: pairs[i].activeContacts[0].vertex.x, - y: pairs[i].activeContacts[0].vertex.y, - radius: dmg * 500, - color: game.mobDmgColor, - time: game.drawTime - }); + if (mech.collisionImmune < mech.cycle && (obj === playerBody || obj === playerHead)) { + mech.collisionImmune = mech.cycle + b.modCollisionImmuneCycles; //player is immune to collision damage for 30 cycles + mob[k].foundPlayer(); + let dmg = Math.min(Math.max(0.025 * Math.sqrt(mob[k].mass), 0.05), 0.3) * game.dmgScale; //player damage is capped at 0.3*dmgScale of 1.0 + mech.damage(dmg); + if (mob[k].onHit) mob[k].onHit(k); + if (b.isModPiezo) mech.fieldMeter = mech.fieldEnergyMax; + if (b.isModAnnihilation && mob[k].dropPowerUp && !mob[k].isShielded) { + mob[k].death(); + game.drawList.push({ + //add dmg to draw queue + x: pairs[i].activeContacts[0].vertex.x, + y: pairs[i].activeContacts[0].vertex.y, + radius: dmg * 2000, + color: "rgba(255,0,255,0.2)", + time: game.drawTime + }); + } else { + game.drawList.push({ + //add dmg to draw queue + x: pairs[i].activeContacts[0].vertex.x, + y: pairs[i].activeContacts[0].vertex.y, + radius: dmg * 500, + color: game.mobDmgColor, + time: game.drawTime + }); - } - //extra kick between player and mob //this section would be better with forces but they don't work... - let angle = Math.atan2(player.position.y - mob[k].position.y, player.position.x - mob[k].position.x); - Matter.Body.setVelocity(player, { - x: player.velocity.x + 8 * Math.cos(angle), - y: player.velocity.y + 8 * Math.sin(angle) - }); - Matter.Body.setVelocity(mob[k], { - x: mob[k].velocity.x - 8 * Math.cos(angle), - y: mob[k].velocity.y - 8 * Math.sin(angle) - }); - return; } + //extra kick between player and mob //this section would be better with forces but they don't work... + let angle = Math.atan2(player.position.y - mob[k].position.y, player.position.x - mob[k].position.x); + Matter.Body.setVelocity(player, { + x: player.velocity.x + 8 * Math.cos(angle), + y: player.velocity.y + 8 * Math.sin(angle) + }); + Matter.Body.setVelocity(mob[k], { + x: mob[k].velocity.x - 8 * Math.cos(angle), + y: mob[k].velocity.y - 8 * Math.sin(angle) + }); + return; } //mob + bullet collisions if (obj.classType === "bullet" && obj.speed > obj.minDmgSpeed) { diff --git a/js/game.js b/js/game.js index 4f3e9ff..4e58eda 100644 --- a/js/game.js +++ b/js/game.js @@ -463,7 +463,7 @@ const game = { if (game.difficultyMode === 0) { game.isEasyMode = true; game.difficultyMode = 1 - level.difficultyDecrease(6); + level.difficultyDecrease(6); //if this stops being -6 change in build.calculateCustomDifficulty() } game.clearNow = true; diff --git a/js/index.js b/js/index.js index 5e8d6ce..e139944 100644 --- a/js/index.js +++ b/js/index.js @@ -117,34 +117,6 @@ game mechanics */ -// local storage -let localSettings = JSON.parse(localStorage.getItem("localSettings")); -// console.log(localSettings) -if (localSettings) { - game.isBodyDamage = localSettings.isBodyDamage - document.getElementById("body-damage").checked = localSettings.isBodyDamage - - game.difficultyMode = localSettings.difficultyMode - document.getElementById("difficulty-select").value = localSettings.difficultyMode - - if (localSettings.fpsCapDefault === 'max') { - game.fpsCapDefault = 999999999; - } else { - game.fpsCapDefault = Number(localSettings.fpsCapDefault) - } - document.getElementById("fps-select").value = localSettings.fpsCapDefault -} else { - localSettings = { - isBodyDamage: true, - difficultyMode: '1', - fpsCapDefault: '72', - }; - localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage - document.getElementById("body-damage").checked = localSettings.isBodyDamage - document.getElementById("difficulty-select").value = localSettings.difficultyMode - document.getElementById("fps-select").value = localSettings.fpsCapDefault -} - //collision groups // cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet | cat.mobShield const cat = { @@ -222,19 +194,77 @@ const build = { who.innerHTML = `
  ${b.mods[index].name}
${b.mods[index].description}` } } - document.title = `effective starting level: ${build.list.length * game.difficultyMode}` - // document.getElementById("starting-level").innerHTML = `effective starting level: ${build.list.length * game.difficultyMode}` + // document.title = `effective starting level: ${build.list.length * game.difficultyMode}` + build.calculateCustomDifficulty() }, - removeMod(index) { - for (let i = build.list.length - 1; i > -1; i--) { - if (build.list[i].type === "mod" && build.list[i].index === index) build.list.splice(i, 1); + makeGrid() { + let text = + `
+ + + start + + + + + reset + + +
+
+
+ + +
` + for (let i = 1, len = mech.fieldUpgrades.length; i < len; i++) { + text += `
  ${mech.fieldUpgrades[i].name}
${mech.fieldUpgrades[i].description}
` } + for (let i = 0, len = b.guns.length; i < len; i++) { + text += `
  ${b.guns[i].name}
${b.guns[i].description}
` + } + for (let i = 0, len = b.mods.length; i < len; i++) { + if (b.mods[i].name === "Born rule" || b.mods[i].name === "+1 cardinality") { + text += `
  ${b.mods[i].name}
${b.mods[i].description}
` + } else { + text += `
  ${b.mods[i].name}
${b.mods[i].description}
` + } + } + const el = document.getElementById("build-grid") + el.innerHTML = text + el.style.display = "none" + + document.getElementById("difficulty-select-custom").addEventListener("input", () => { + document.getElementById("difficulty-select").value = document.getElementById("difficulty-select-custom").value + game.difficultyMode = Number(document.getElementById("difficulty-select-custom").value) + localSettings.difficultyMode = game.difficultyMode + localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage + build.calculateCustomDifficulty() + }); + }, + reset() { + build.list = [] + build.makeGrid(); + document.getElementById("build-grid").style.display = "grid" + build.calculateCustomDifficulty() + document.getElementById("difficulty-select-custom").value = localSettings.difficultyMode + }, + calculateCustomDifficulty() { + let difficulty = build.list.length * game.difficultyMode + if (game.difficultyMode === 0) difficulty = build.list.length * 1 - 6 + document.getElementById("starting-level").innerHTML = `starting level: ${difficulty}` }, startBuildRun() { spawn.setSpawnList(); spawn.setSpawnList(); //gives random mobs, not starter game.startGame(); - level.difficultyIncrease(build.list.length * game.difficultyMode) + let difficulty = build.list.length * game.difficultyMode - 1 + if (game.difficultyMode === 0) difficulty = build.list.length * 1 - 6 - 1 + level.difficultyIncrease(difficulty) level.isBuildRun = true; for (let i = 0; i < build.list.length; i++) { @@ -249,6 +279,8 @@ const build = { } } +build.makeGrid(); + document.getElementById("build-button").addEventListener("click", () => { document.getElementById("build-button").style.display = "none"; const el = document.getElementById("build-grid") @@ -260,40 +292,45 @@ document.getElementById("build-button").addEventListener("click", () => { } else { build.list = [] // let text = '

The difficulty increases by one level for each power up you choose.

' - let text = - `
- - - start - - -
-
- each power up you select will increase the starting level by one -
` - for (let i = 1, len = mech.fieldUpgrades.length; i < len; i++) { - text += `
  ${mech.fieldUpgrades[i].name}
${mech.fieldUpgrades[i].description}
` - } - for (let i = 0, len = b.guns.length; i < len; i++) { - text += `
  ${b.guns[i].name}
${b.guns[i].description}
` - } - for (let i = 0, len = b.mods.length; i < len; i++) { - if (b.mods[i].name === "Born rule" || b.mods[i].name === "Bayesian inference" || b.mods[i].name === "+1 cardinality") { - text += `
  ${b.mods[i].name}
${b.mods[i].description}
` - } else { - text += `
  ${b.mods[i].name}
${b.mods[i].description}
` - } - } - el.innerHTML = text - el.style.display = "grid" build.isShowingBuilds = true + el.style.display = "grid" document.body.style.overflowY = "scroll"; document.body.style.overflowX = "hidden"; document.getElementById("info").style.display = 'none' } + build.calculateCustomDifficulty() }); +// local storage +let localSettings = JSON.parse(localStorage.getItem("localSettings")); +// console.log(localSettings) +if (localSettings) { + game.isBodyDamage = localSettings.isBodyDamage + document.getElementById("body-damage").checked = localSettings.isBodyDamage + + game.difficultyMode = localSettings.difficultyMode + document.getElementById("difficulty-select").value = localSettings.difficultyMode + document.getElementById("difficulty-select-custom").value = localSettings.difficultyMode + + if (localSettings.fpsCapDefault === 'max') { + game.fpsCapDefault = 999999999; + } else { + game.fpsCapDefault = Number(localSettings.fpsCapDefault) + } + document.getElementById("fps-select").value = localSettings.fpsCapDefault +} else { + localSettings = { + isBodyDamage: true, + difficultyMode: '1', + fpsCapDefault: '72', + }; + localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage + document.getElementById("body-damage").checked = localSettings.isBodyDamage + document.getElementById("difficulty-select").value = localSettings.difficultyMode + document.getElementById("fps-select").value = localSettings.fpsCapDefault +} + //set up canvas var canvas = document.getElementById("canvas"); //using "const" causes problems in safari when an ID shares the same name. @@ -385,7 +422,9 @@ document.getElementById("body-damage").addEventListener("input", () => { localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage }); +// difficulty-select-custom event listener is set in build.makeGrid document.getElementById("difficulty-select").addEventListener("input", () => { + document.getElementById("difficulty-select-custom").value = document.getElementById("difficulty-select").value game.difficultyMode = Number(document.getElementById("difficulty-select").value) localSettings.difficultyMode = game.difficultyMode localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage diff --git a/js/level.js b/js/level.js index 4f32c00..dba9390 100644 --- a/js/level.js +++ b/js/level.js @@ -1477,7 +1477,7 @@ const level = { level.onLevel++; //cycles map to next level if (level.onLevel > level.levels.length - 1) level.onLevel = 0; - level.difficultyIncrease(game.difficultyMode + level.isBuildRun) //increase difficulty based on modes + level.difficultyIncrease(game.difficultyMode) //increase difficulty based on modes if (game.isEasyMode && level.levelsCleared % 2) level.difficultyDecrease(1); game.clearNow = true; //triggers in game.clearMap to remove all physics bodies and setup for new map } diff --git a/js/player.js b/js/player.js index 6eb87de..d31a345 100644 --- a/js/player.js +++ b/js/player.js @@ -895,7 +895,7 @@ const mech = { pushMass(who) { const speed = Vector.magnitude(Vector.sub(who.velocity, player.velocity)) const fieldBlockCost = 0.03 + Math.sqrt(who.mass) * speed * 0.003 //0.012 - if (mech.fieldMeter > fieldBlockCost * 0.6) { //shield needs at least some of the cost to block + if (mech.fieldMeter > fieldBlockCost * 0.2) { //shield needs at least some of the cost to block mech.fieldMeter -= fieldBlockCost * mech.fieldShieldingScale; if (mech.fieldMeter < 0) mech.fieldMeter = 0; mech.drawHold(who); diff --git a/js/powerups.js b/js/powerups.js index 85febd0..55744af 100644 --- a/js/powerups.js +++ b/js/powerups.js @@ -75,8 +75,9 @@ const powerUps = { } } } else { - //if you don't have any guns just add ammo to a random gun you don't have yet - target = b.guns[Math.floor(Math.random() * b.guns.length)]; + // target = b.guns[Math.floor(Math.random() * b.guns.length)]; //if you don't have any guns just add ammo to a random gun you don't have yet + mech.fieldMeter = mech.fieldEnergyMax; + if (!game.lastLogTime) game.makeTextLog("+energy", 300); } if (target.ammo === Infinity) { mech.fieldMeter = mech.fieldEnergyMax; @@ -253,16 +254,12 @@ const powerUps = { powerUps.spawn(x, y, "heal"); powerUps.spawn(x, y, "heal"); powerUps.spawn(x, y, "heal"); - if (Math.random() < b.isModBayesian) { - powerUps.spawn(x, y, "heal"); - } + if (Math.random() < b.isModBayesian) powerUps.spawn(x, y, "heal"); } else { powerUps.spawn(x, y, "ammo"); powerUps.spawn(x, y, "ammo"); powerUps.spawn(x, y, "ammo"); - if (Math.random() < b.isModBayesian) { - powerUps.spawn(x, y, "ammo"); - } + if (Math.random() < b.isModBayesian) powerUps.spawn(x, y, "ammo"); } }, chooseRandomPowerUp(x, y) { //100% chance to drop a random power up //used in spawn.debris diff --git a/style.css b/style.css index e82112d..4c70aac 100644 --- a/style.css +++ b/style.css @@ -14,6 +14,10 @@ canvas { z-index: 0; } +select { + font-size: 0.8em; +} + #splash { user-select: none; position: absolute;