diff --git a/js/bullets.js b/js/bullets.js index 8ac9824..fe03f00 100644 --- a/js/bullets.js +++ b/js/bullets.js @@ -85,6 +85,7 @@ const b = { isModDeterminism: null, isModHarmReduce: null, modNailsDeathMob: null, + isModSlowFPS: null, modOnHealthChange() { //used with acid mod if (b.isModAcidDmg && mech.health > 0.8) { b.modAcidDmg = 0.5 @@ -234,6 +235,22 @@ const b = { b.isModHarmDamage = false; } }, + { + name: "acute stress response", + description: "increase damage by 33%
but, after a mob dies lose 1/2 your energy", + maxCount: 1, + count: 0, + allowed() { + return !b.isModEnergyHealth + }, + requires: "mass-energy equivalence", + effect() { + b.isModEnergyLoss = true; + }, + remove() { + b.isModEnergyLoss = false; + } + }, { name: "auto-loading heuristics", description: "your delay after firing is +14% shorter", @@ -473,22 +490,6 @@ const b = { b.isModEnergyRecovery = false; } }, - { - name: "acute stress response", - description: "increase damage by 33%
but, after a mob dies lose 1/2 your energy", - maxCount: 1, - count: 0, - allowed() { - return !b.isModEnergyHealth - }, - requires: "mass-energy equivalence", - effect() { - b.isModEnergyLoss = true; - }, - remove() { - b.isModEnergyLoss = false; - } - }, { name: "squirrel-cage rotor", description: "jump higher and move faster
reduced harm from falling ", @@ -526,6 +527,22 @@ const b = { b.modCollisionImmuneCycles = 30; } }, + { + name: "clock gating", + description: `reduce all harm by 15%
slow time by 50% after receiving harm`, + maxCount: 1, + count: 0, + allowed() { + return game.fpsCapDefault > 45 + }, + requires: "FPS above 45", + effect() { + b.isModSlowFPS = true; + }, + remove() { + b.isModSlowFPS = true; + } + }, { name: "quantum immortality", description: "after dying, continue in an alternate reality
guns, ammo, field, and mods are randomized", @@ -642,7 +659,7 @@ const b = { }, { name: "energy conservation", - description: "15% of damage done is recovered as energy", + description: "+15% of damage done recovered as energy", maxCount: 9, count: 0, allowed() { @@ -659,7 +676,7 @@ const b = { }, { name: "entropy exchange", - description: "heal for 1.5% of damage done", + description: "heal for +1.5% of damage done", maxCount: 9, count: 0, allowed() { @@ -711,7 +728,7 @@ const b = { }, { name: "recursive healing", - description: "healing power ups trigger a 2nd time", + description: "healing power ups trigger +1 more time", maxCount: 9, count: 0, allowed() { @@ -758,22 +775,6 @@ const b = { b.modBayesian = 0; } }, - { - name: "cardinality", - description: "one extra choice when selecting power ups", - maxCount: 1, - count: 0, - allowed() { - return true - }, - requires: "", - effect: () => { - b.isModExtraChoice = true; - }, - remove() { - b.isModExtraChoice = false; - } - }, { name: "catabolism", description: "gain ammo when you fire while out of ammo
drains 3% of current remaining health", @@ -790,15 +791,31 @@ const b = { b.isModAmmoFromHealth = 0; } }, + { + name: "cardinality", + description: "2 extra choices when selecting power ups", + maxCount: 1, + count: 0, + allowed() { + return !b.isModDeterminism + }, + requires: "not determinism", + effect: () => { + b.isModExtraChoice = true; + }, + remove() { + b.isModExtraChoice = false; + } + }, { name: "determinism", description: "spawn 4 mods and 2 heal power ups
future power ups are limited to one choice", maxCount: 1, count: 0, allowed() { - return true + return !b.isModExtraChoice }, - requires: "", + requires: "not cardinality", effect: () => { b.isModDeterminism = true; for (let i = 0; i < 4; i++) { //if you change the six also change it in Born rule @@ -1217,7 +1234,7 @@ const b = { maxCount: 1, count: 0, allowed() { - return b.modNailBotCount || b.haveGunCheck("mine") || b.modGrenadeFragments || b.isModRailNails || b.isModBotSpawner + return b.modNailBotCount || b.haveGunCheck("mine") || b.modGrenadeFragments || b.isModRailNails || b.isModBotSpawner || b.modNailsDeathMob }, requires: "nails", effect() { @@ -1350,12 +1367,12 @@ const b = { requires: "laser", effect() { b.modLaserReflections++; - b.modLaserDamage += 0.035; //base is 0.06 + b.modLaserDamage += 0.045; //base is 0.08 b.modLaserFieldDrain += 0.001 //base is 0.002 }, remove() { b.modLaserReflections = 2; - b.modLaserDamage = 0.07; + b.modLaserDamage = 0.09; b.modLaserFieldDrain = 0.002; } }, @@ -2782,7 +2799,7 @@ const b = { count: 0, //used to track how many shots are in a volley before a big CD lastFireCycle: 0, //use to remember how longs its been since last fire, used to reset count fire() { - const CD = (mech.crouch) ? 45 : 25 + const CD = (mech.crouch) ? 50 : 30 if (this.lastFireCycle + CD < mech.cycle) this.count = 0 //reset count if it cycles past the CD this.lastFireCycle = mech.cycle if (this.count > ((mech.crouch) ? 6 : 1)) { @@ -2790,7 +2807,7 @@ const b = { mech.fireCDcycle = mech.cycle + Math.floor(CD * b.modFireRate); // cool down } else { this.count++ - mech.fireCDcycle = mech.cycle + Math.floor(2 * b.modFireRate); // cool down + mech.fireCDcycle = mech.cycle + Math.floor(3 * b.modFireRate); // cool down } function makeFlechette(angle = mech.angle) { diff --git a/js/engine.js b/js/engine.js index 84517ac..34b1d0e 100644 --- a/js/engine.js +++ b/js/engine.js @@ -55,20 +55,20 @@ function playerOffGroundCheck(event) { } } -function playerHeadCheck(event) { - //runs on collisions events - if (mech.crouch) { - mech.isHeadClear = true; - const pairs = event.pairs; - for (let i = 0, j = pairs.length; i != j; ++i) { - if (pairs[i].bodyA === headSensor) { - mech.isHeadClear = false; - } else if (pairs[i].bodyB === headSensor) { - mech.isHeadClear = false; - } - } - } -} +// function playerHeadCheck(event) { +// //runs on collisions events +// if (mech.crouch) { +// mech.isHeadClear = true; +// const pairs = event.pairs; +// for (let i = 0, j = pairs.length; i != j; ++i) { +// if (pairs[i].bodyA === headSensor) { +// mech.isHeadClear = false; +// } else if (pairs[i].bodyB === headSensor) { +// mech.isHeadClear = false; +// } +// } +// } +// } function collisionChecks(event) { const pairs = event.pairs; @@ -249,12 +249,12 @@ function collisionChecks(event) { //determine if player is on the ground Events.on(engine, "collisionStart", function (event) { playerOnGroundCheck(event); - playerHeadCheck(event); + // playerHeadCheck(event); collisionChecks(event); }); Events.on(engine, "collisionActive", function (event) { playerOnGroundCheck(event); - playerHeadCheck(event); + // playerHeadCheck(event); }); Events.on(engine, "collisionEnd", function (event) { playerOffGroundCheck(event); diff --git a/js/level.js b/js/level.js index 0d88890..779fc80 100644 --- a/js/level.js +++ b/js/level.js @@ -14,13 +14,13 @@ const level = { start() { if (build.isURLBuild && level.levelsCleared === 0) build.onLoadPowerUps(); if (level.levelsCleared === 0) { //this code only runs on the first level - // game.enableConstructMode() //used to build maps in testing mode + game.enableConstructMode() //used to build maps in testing mode // level.difficultyIncrease(9) // b.giveGuns("foam") // mech.setField("time dilation field") // b.giveMod("renormalization"); // b.giveMod("impact shear"); - // b.giveMod("nail bot"); + b.giveMod("clock gating"); // b.giveGuns("mine") // mech.setField("pilot wave") // mech.setField("perfect diamagnetism") @@ -102,7 +102,7 @@ const level = { //****************************************************************************************************************** testing() { - level.difficultyIncrease(19); + // level.difficultyIncrease(19); spawn.setSpawnList(); spawn.setSpawnList(); level.defaultZoom = 1500 @@ -157,8 +157,8 @@ const level = { // spawn.bomberBoss(2900, -500) // spawn.suckerBoss(1200, -500) - // spawn.hopper(1200, -500, 70) - spawn.spinner(1200, -500) + spawn.hopper(1200, -500) + spawn.laser(1200, -500) // spawn.shield(mob[mob.length - 1], 1200, -500, 1); // spawn.nodeBoss(1200, -500, "spiker") diff --git a/js/player.js b/js/player.js index f885eb5..08c9df1 100644 --- a/js/player.js +++ b/js/player.js @@ -76,7 +76,7 @@ const mech = { standingOn: undefined, numTouching: 0, crouch: false, - isHeadClear: true, + // isHeadClear: true, spawnPos: { x: 0, y: 0 @@ -179,11 +179,18 @@ const mech = { } }, hardLandCD: 0, + checkHeadClear() { + if (Matter.Query.collides(headSensor, map).length > 0) { + return false + } else { + return true + } + }, enterAir() { //triggered in engine.js on collision mech.onGround = false; mech.hardLandCD = 0 // disable hard landing - if (mech.isHeadClear) { + if (mech.checkHeadClear()) { if (mech.crouch) { mech.undoCrouch(); } @@ -194,7 +201,7 @@ const mech = { enterLand() { mech.onGround = true; if (mech.crouch) { - if (mech.isHeadClear) { + if (mech.checkHeadClear()) { mech.undoCrouch(); } else { mech.yOffGoal = mech.yOffWhen.crouch; @@ -230,7 +237,7 @@ const mech = { keyMove() { if (mech.onGround) { //on ground ********************** if (mech.crouch) { - if (!(keys[83] || keys[40]) && mech.isHeadClear && mech.hardLandCD < mech.cycle) mech.undoCrouch(); + if (!(keys[83] || keys[40]) && mech.checkHeadClear() && mech.hardLandCD < mech.cycle) mech.undoCrouch(); } else if (keys[83] || keys[40] || mech.hardLandCD > mech.cycle) { mech.doCrouch(); //on ground && not crouched and pressing s or down } else if ((keys[87] || keys[38]) && mech.buttonCD_jump + 20 < mech.cycle && mech.yOffWhen.stand > 23) { @@ -506,6 +513,7 @@ const mech = { harmReduction() { let dmg = 1 dmg *= mech.fieldDamageResistance + dmg *= b.isModSlowFPS ? 0.85 : 1 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++) { @@ -586,8 +594,6 @@ const mech = { // game.makeTextLog("death avoided", 360); b.isModDeathAvoidOnCD = false; }, 3000); - - return; } else { mech.health = 0; mech.death(); @@ -596,22 +602,13 @@ const mech = { } } + if (dmg > 0.2 * mech.holdingMassScale) mech.drop(); //drop block if holding + b.modOnHealthChange(); mech.displayHealth(); document.getElementById("dmg").style.transition = "opacity 0s"; document.getElementById("dmg").style.opacity = 0.1 + Math.min(0.6, dmg * 4); - // freeze game and display a full screen red color - if (dmg > 0.05) { - if (dmg > 0.20 * mech.holdingMassScale) mech.drop(); //drop block if holding - game.fpsCap = 4 //40 - Math.min(25, 100 * dmg) - game.fpsInterval = 1000 / game.fpsCap; - } else { - game.fpsCap = game.fpsCapDefault - game.fpsInterval = 1000 / game.fpsCap; - } - mech.defaultFPSCycle = mech.cycle - const normalFPS = function () { if (mech.defaultFPSCycle < mech.cycle) { //back to default values game.fpsCap = game.fpsCapDefault @@ -622,33 +619,23 @@ const mech = { requestAnimationFrame(normalFPS); } }; - requestAnimationFrame(normalFPS); - // // freeze game and display a full screen red color - // if (dmg > 0.05) { - // if (dmg > 0.07) { - // mech.drop(); //drop block if holding - // } - - // game.fpsCap = 4 //40 - Math.min(25, 100 * dmg) - // game.fpsInterval = 1000 / game.fpsCap; - // } else { - // game.fpsCap = game.fpsCapDefault - // game.fpsInterval = 1000 / game.fpsCap; - // } - // mech.defaultFPSCycle = mech.cycle - - // const normalFPS = function () { - // if (mech.defaultFPSCycle < mech.cycle) { //back to default values - // game.fpsCap = game.fpsCapDefault - // game.fpsInterval = 1000 / game.fpsCap; - // document.getElementById("dmg").style.transition = "opacity 1s"; - // document.getElementById("dmg").style.opacity = "0"; - // } else { - // requestAnimationFrame(normalFPS); - // } - // }; - // requestAnimationFrame(normalFPS); + if (mech.defaultFPSCycle < mech.cycle) requestAnimationFrame(normalFPS); + if (b.isModSlowFPS) { // slow game + game.fpsCap = 30 //new fps + game.fpsInterval = 1000 / game.fpsCap; + mech.defaultFPSCycle = mech.cycle + 30 //how long to wait to return to normal fps + if (dmg > 0.1) mech.defaultFPSCycle += 30 + } else { + if (dmg > 0.05) { // freeze game for high damage hits + game.fpsCap = 4 //40 - Math.min(25, 100 * dmg) + game.fpsInterval = 1000 / game.fpsCap; + } else { + game.fpsCap = game.fpsCapDefault + game.fpsInterval = 1000 / game.fpsCap; + } + mech.defaultFPSCycle = mech.cycle + } }, hitMob(i, dmg) { //prevents damage happening too quick diff --git a/js/powerups.js b/js/powerups.js index 20d99a1..43fd55c 100644 --- a/js/powerups.js +++ b/js/powerups.js @@ -47,7 +47,7 @@ const powerUps = { return 40 * Math.sqrt(0.1 + Math.random() * 0.5); }, effect() { - if (!b.isModEnergyHealth) { + if (!b.isModEnergyHealth && mech.alive) { let heal = 0 for (let i = 0; i < b.modRecursiveHealing; i++) heal += ((this.size / 40) ** 2) if (heal > 0) { @@ -101,10 +101,10 @@ const powerUps = { return 45; }, effect() { - function pick(who, skip1 = -1, skip2 = -1, skip3 = -1) { + function pick(who, skip1 = -1, skip2 = -1, skip3 = -1, skip4 = -1) { let options = []; for (let i = 1; i < who.length; i++) { - if (i !== mech.fieldMode && (!game.isEasyToAimMode || mech.fieldUpgrades[i].isEasyToAim) && i !== skip1 && i !== skip2 && i !== skip3) options.push(i); + if (i !== mech.fieldMode && (!game.isEasyToAimMode || mech.fieldUpgrades[i].isEasyToAim) && i !== skip1 && i !== skip2 && i !== skip3 && i !== skip4) options.push(i); } if (options.length > 0) return options[Math.floor(Math.random() * options.length)] } @@ -124,6 +124,8 @@ const powerUps = { if (b.isModExtraChoice) { let choice4 = pick(mech.fieldUpgrades, choice1, choice2, choice3) if (choice4 > -1) text += `
  ${mech.fieldUpgrades[choice4].name}
${mech.fieldUpgrades[choice4].description}
` + let choice5 = pick(mech.fieldUpgrades, choice1, choice2, choice3, choice4) + if (choice5 > -1) text += `
  ${mech.fieldUpgrades[choice5].name}
${mech.fieldUpgrades[choice5].description}
` } // text += `
${game.SVGrightMouse} activate the shield with the right mouse
fields shield you from damage
and let you pick up and throw blocks
` document.getElementById("choose-grid").innerHTML = text @@ -140,14 +142,10 @@ const powerUps = { return 42; }, effect() { - function pick(skip1 = -1, skip2 = -1, skip3 = -1) { + function pick(skip1 = -1, skip2 = -1, skip3 = -1, skip4 = -1) { let options = []; for (let i = 0; i < b.mods.length; i++) { - if ( - b.mods[i].count < b.mods[i].maxCount && - i !== skip1 && i !== skip2 && i !== skip3 && - b.mods[i].allowed() - ) { + if (b.mods[i].count < b.mods[i].maxCount && i !== skip1 && i !== skip2 && i !== skip3 && i !== skip4 && b.mods[i].allowed()) { options.push(i); } } @@ -169,6 +167,8 @@ const powerUps = { if (b.isModExtraChoice) { let choice4 = pick(choice1, choice2, choice3) if (choice4 > -1) text += `
  ${b.mods[choice4].name}
${b.mods[choice4].description}
` + let choice5 = pick(choice1, choice2, choice3, choice4) + if (choice5 > -1) text += `
  ${b.mods[choice5].name}
${b.mods[choice5].description}
` } document.getElementById("choose-grid").innerHTML = text powerUps.showDraft(); @@ -184,10 +184,10 @@ const powerUps = { return 35; }, effect() { - function pick(who, skip1 = -1, skip2 = -1, skip3 = -1) { + function pick(who, skip1 = -1, skip2 = -1, skip3 = -1, skip4 = -1) { let options = []; for (let i = 0; i < who.length; i++) { - if (!who[i].have && (!game.isEasyToAimMode || b.guns[i].isEasyToAim) && i !== skip1 && i !== skip2 && i !== skip3) options.push(i); + if (!who[i].have && (!game.isEasyToAimMode || b.guns[i].isEasyToAim) && i !== skip1 && i !== skip2 && i !== skip3 && i !== skip4) options.push(i); } if (options.length > 0) return options[Math.floor(Math.random() * options.length)] } @@ -207,6 +207,8 @@ const powerUps = { if (b.isModExtraChoice) { let choice4 = pick(b.guns, choice1, choice2, choice3) if (choice4 > -1) text += `
  ${b.guns[choice4].name}
${b.guns[choice4].description}
` + let choice5 = pick(b.guns, choice1, choice2, choice3, choice4) + if (choice5 > -1) text += `
  ${b.guns[choice5].name}
${b.guns[choice5].description}
` } document.getElementById("choose-grid").innerHTML = text powerUps.showDraft(); diff --git a/js/spawn.js b/js/spawn.js index 76c0e39..e54645a 100644 --- a/js/spawn.js +++ b/js/spawn.js @@ -906,7 +906,16 @@ const spawn = { this.fill = '#' + Math.random().toString(16).substr(-6); //flash colors // Matter.Body.rotate(this, -0.003 / (0.3 + this.health)) // if (!mech.isBodiesAsleep) Matter.Body.rotate(me, this.rotateVelocity) - Matter.Body.setAngle(me, game.cycle * this.rotateVelocity) + + //check if slowed + let slowed = false + for (let i = 0; i < this.status.length; i++) { + if (this.status[i].type === "slow") { + slowed = true + break + } + } + if (!slowed) Matter.Body.setAngle(me, game.cycle * this.rotateVelocity) // this.torque -= this.inertia * 0.0000025 / (4 + this.health); Matter.Body.setVelocity(this, { diff --git a/todo.txt b/todo.txt index 9eeb0d2..c9a5110 100644 --- a/todo.txt +++ b/todo.txt @@ -1,9 +1,23 @@ - -mod - negative mass field: 80%->90% harm reduction while active, but 2x energy drain -mod - mobs fire nails when they die (by Francois 👑 from discord) - +cardinality now gives 2 selection choices ++20% laser damage +Mod: When damaged, time slows down ************** TODO - n-gon ************** +let people know about n-gon + blips - errant signal on youtube + reddit - r/IndieGaming + hacker news - show hacker news post + +frozen mobs take +33% damage + +a lasting AoE damage gun + reuse sporangium code + maybe mod for vacuum bomb where it does aoe damage before it explodes + +bot that punches nearby mobs + bot could have a regeneration phase, and a punching phase + indicate phase by the size, shape of bot + possible names for mods Hypergolic - A hypergolic propellant combination used in a rocket engine is one whose components spontaneously ignite when they come into contact with each other. @@ -26,15 +40,9 @@ construct display current output text in a box live update it -lore - a robot (the player) gains self awareness - each mod/gun/field is a new tech - all the technology leads to the singularity - each game run is actually the mech simulating a possible escape - this is why the graphics are so bad, its just a simulation - final mod is "this is just a simulation" - you get immortality and Infinity damage - the next level is the final level - when you die with Quantum Immortality there is a chance of lore text +boss levels - small levels just a boss, and maybe a few mobs + boss level for timeSkipBoss because of game instability for boss on normal levels + this might not fix issues atmosphere levels: change the pace, give the user a rest between combat low or no combat, but more graphics @@ -50,6 +58,16 @@ atmosphere levels: change the pace, give the user a rest between combat you shoot your self to wake up? nonaggressive mobs +lore - a robot (the player) gains self awareness + each mod/gun/field is a new tech + all the technology leads to the singularity + each game run is actually the mech simulating a possible escape + this is why the graphics are so bad, its just a simulation + final mod is "this is just a simulation" + you get immortality and Infinity damage + the next level is the final level + when you die with Quantum Immortality there is a chance of lore text + boss mob - let it die multiple times and come back to life on death event spawns a new version of self, but with a decrementing counter @@ -75,18 +93,8 @@ mod - killing a stunned mob gives something mod - scale squirrel cage rotor with current energy is variable speed going to be hard to deal with? -boss level for timeSkipBoss because of game instability for boss on normal levels - boss level needs to be very simple (maybe no other mobs, or no random mobs) - mod - you can no longer see your current health -boss mob - just a faster and larger version of a springer mob - could have a more frequent random walk - always shielded - consider combining with time skipper field? - -mob - time skipper: sends a pulse wave out that will cause time to jump forward 1 second. - mob sniper - targeting laser, then a high speed, no gravity bullet mod - increase laser bot range, and reduce energy drain @@ -100,8 +108,6 @@ settings - custom keys binding css transition for pause menu -mod - do more damage when not moving? - gun/field: portals use the code from mines to get them to stick to walls or lasers @@ -119,11 +125,6 @@ gun: Spirit Bomb (singularity) uses energy hold above the player's head -small Boss levels - sensor that locks you in after you enter the boss room - boss that eats other mobs and gains stats from them - chance to spawn on any level (past level 5) - add a key that player picks up and needs to set on the exit door to open it make power ups keep moving to player if the pickup field is turned off before they get picked up