From 6c51916f04f19b6b2b5a2130eba8573325253a14 Mon Sep 17 00:00:00 2001 From: landgreen Date: Sat, 5 Sep 2020 06:01:47 -0700 Subject: [PATCH] exciton-lattice field: perfect diamagnetism is a bit larger can now grab power ups from far away mod: exciton-lattice - reduce harm by 80%, but after taking collision damage eject a random mod eject extra mods if you have recursive stacks power ups have a bit more air friction power ups must be in line of sight to be pulled by the player why mode now gets 100% chance for a second boss power up (up from 50%) this should let why mode reach more interesting build depth laser and pulse got a damage and energy use buff immune to harm for a second after exiting the power up selection menu --- js/bullet.js | 10 ++-- js/engine.js | 15 ++++++ js/game.js | 79 ++++++++++++++++++++++++++++ js/level.js | 4 +- js/mods.js | 47 +++++++++++------ js/player.js | 74 +++++++++++++++++++------- js/powerup.js | 143 ++++++++++++++++++++++++++------------------------ todo.txt | 82 ++++++++++------------------- 8 files changed, 289 insertions(+), 165 deletions(-) diff --git a/js/bullet.js b/js/bullet.js index 77b0c86..ce62235 100644 --- a/js/bullet.js +++ b/js/bullet.js @@ -670,7 +670,7 @@ const b = { }, drone(speed = 1) { const me = bullet.length; - const THRUST = mod.isFastDrones ? 0.0025 : 0.0015 + const THRUST = mod.isFastDrones ? 0.0023 : 0.0015 // const FRICTION = mod.isFastDrones ? 0.008 : 0.0005 const dir = mech.angle + 0.4 * (Math.random() - 0.5); const RADIUS = (4.5 + 3 * Math.random()) @@ -2550,7 +2550,7 @@ const b = { name: "drones", description: "deploy drones that crash into mobs
crashes reduce their lifespan by 1 second", ammo: 0, - ammoPack: 13, + ammoPack: 14, have: false, fire() { b.drone(mech.crouch ? 45 : 1) @@ -3173,8 +3173,8 @@ const b = { }; if (mod.isPulseAim) { //find mobs in line of sight let dist = 2200 - energy = 0.25 * Math.min(mech.energy, 1.75) - explosionRange = 1100 * energy + energy = 0.23 * Math.min(mech.energy, 1.75) + explosionRange = 1300 * energy for (let i = 0, len = mob.length; i < len; i++) { const newDist = Vector.magnitude(Vector.sub(path[0], mob[i].position)) if (explosionRange < newDist && @@ -3206,7 +3206,7 @@ const b = { } else { energy = 0.3 * Math.min(mech.energy, 1.75) mech.energy -= energy * mod.isLaserDiode - explosionRange = 1100 * energy + explosionRange = 1200 * energy if (best.who) b.explosion(path[1], explosionRange, true) mech.fireCDcycle = mech.cycle + Math.floor(50 * b.fireCD); // cool down } diff --git a/js/engine.js b/js/engine.js index e86ba81..12d5600 100644 --- a/js/engine.js +++ b/js/engine.js @@ -162,6 +162,21 @@ function collisionChecks(event) { dmg *= 0.85 } mech.damage(dmg); + if (mod.isEjectMod) { + const have = [] //find which mods you have + for (let i = 0; i < mod.mods.length; i++) { + if (mod.mods[i].count > 0) have.push(i) + } + const choose = have[Math.floor(Math.random() * have.length)] + //message about what mod was lost + game.makeTextLog(`
  ${mod.mods[choose].name} ejected by exciton-lattice`, 300) + + + for (let i = 0; i < mod.mods[choose].count; i++) powerUps.spawn(mech.pos.x, mech.pos.y, "mod"); + mod.mods[choose].count = 0; + mod.mods[choose].remove(); // remove a random mod form the list of mods you have + game.updateModHUD(); + } if (mob[k].onHit) mob[k].onHit(k); //extra kick between player and mob //this section would be better with forces but they don't work... diff --git a/js/game.js b/js/game.js index 9739958..a25e02f 100644 --- a/js/game.js +++ b/js/game.js @@ -43,6 +43,7 @@ const game = { // game.clip(); ctx.restore(); game.drawCursor(); + // game.pixelGraphics(); }, testingLoop() { game.gravity(); @@ -153,6 +154,84 @@ const game = { // clip() { // }, + pixelGraphics() { + //copy current canvas pixel data + let imgData = ctx.getImageData(0, 0, canvas.width, canvas.height); + let data = imgData.data; + //change pixel data + + + // const off = 4 * Math.floor(x) + 4 * canvas.width * Math.floor(y); + // multiple windows + for (let i = data.length / 2; i < data.length; i += 4) { + index = i % (canvas.width * canvas.height * 2) // + canvas.width*4*canvas.height + + data[i + 0] = data[index + 0]; // red + data[i + 1] = data[index + 1]; // red + data[i + 2] = data[index + 2]; // red + data[i + 3] = data[index + 3]; // red + } + + for (let x = 0; x < len; x++) { + + } + + + + // const startX = 2 * canvas.width + 2 * canvas.width * canvas.height + // const endX = 4 * canvas.width + 4 * canvas.width * canvas.height + // const startY = 2 * canvas.width + 2 * canvas.width * canvas.height + // const endY = 4 * canvas.width + 4 * canvas.width * canvas.height + // for (let x = startX; x < endX; x++) { + // for (let y = startY; y < endY; y++) { + + // } + // } + + + + + //strange draw offset + // const off = canvas.height * canvas.width * 4 / 2 + // for (let index = 0; index < data.length; index += 4) { + // data[index + 0] = data[index + 0 + off]; // red + // data[index + 1] = data[index + 1 + off]; // red + // data[index + 2] = data[index + 2 + off]; // red + // data[index + 3] = data[index + 3 + off]; // red + // } + + //change all pixels + // for (let index = 0; index < data.length; index += 4) { + // data[index + 0] = 255; // red + // data[index + 1] = 255; // green + // data[index + 2] = 255; // blue + // data[index + 3] = 255; // alpha + // } + + //change random pixels + // for (let i = 0, len = Math.floor(data.length / 10); i < len; ++i) { + // const index = Math.floor((Math.random() * data.length) / 4) * 4; + // data[index + 0] = 255; // red + // data[index + 1] = 0; // green + // data[index + 2] = 0; // blue + // data[index + 3] = 255 //Math.floor(Math.random() * Math.random() * 255); // alpha + // } + + // //change random pixels + // for (let i = 0, len = Math.floor(data.length / 1000); i < len; ++i) { + // const index = Math.floor((Math.random() * data.length) / 4) * 4; + // // data[index] = data[index] ^ 255; // Invert Red + // // data[index + 1] = data[index + 1] ^ 255; // Invert Green + // // data[index + 2] = data[index + 2] ^ 255; // Invert Blue + // data[index + 0] = 0; // red + // data[index + 1] = 0; // green + // data[index + 2] = 0; // blue + // // data[index + 3] = 255 //Math.floor(Math.random() * Math.random() * 255); // alpha + // } + + //draw new pixel data to canvas + ctx.putImageData(imgData, 0, 0); + }, drawCursor() { const size = 10; ctx.beginPath(); diff --git a/js/level.js b/js/level.js index e63ce1b..02875fd 100644 --- a/js/level.js +++ b/js/level.js @@ -16,9 +16,9 @@ const level = { // game.zoomScale = 1000; // game.setZoom(); // mech.isStealth = true; - // mech.setField("standing wave harmonics") + // mech.setField("time dilation field") // b.giveGuns("rail gun") - // mod.giveMod("capacitor bank"); + // mod.giveMod("quantum immortality"); level.intro(); //starting level // level.testing(); //not in rotation diff --git a/js/mods.js b/js/mods.js index c0893bf..e3c8514 100644 --- a/js/mods.js +++ b/js/mods.js @@ -86,7 +86,7 @@ const mod = { if (mod.isAcidDmg && mech.health > 1) dmg *= 1.4; if (mod.isRest && player.speed < 1) dmg *= 1.20; if (mod.isEnergyDamage) dmg *= 1 + mech.energy / 5.5; - if (mod.isDamageFromBulletCount) dmg *= 1 + bullet.length * 0.004 + if (mod.isDamageFromBulletCount) dmg *= 1 + bullet.length * 0.0038 if (mod.isRerollDamage) dmg *= 1 + 0.05 * powerUps.reroll.rerolls if (mod.isOneGun && b.inventory.length < 2) dmg *= 1.25 return dmg * mod.slowFire @@ -713,6 +713,22 @@ const mod = { mod.isHarmArmor = false; } }, + { + name: "exciton-lattice", + description: `reduce harm by 80%, but
after a collision, eject one of your mods`, + maxCount: 1, + count: 0, + allowed() { + return !mod.isEnergyHealth && (mod.isBayesian || mod.isExtraChoice || mod.manyWorlds || mod.isImmortal || mod.isMineDrop || mod.renormalization) + }, + requires: "Bayesian, cardinality, many worlds, immortality, renormalization, or mine synthesis", + effect() { + mod.isEjectMod = true; + }, + remove() { + mod.isEjectMod = false; + } + }, { name: "clock gating", description: `slow time by 50% after receiving harm
reduce harm by 15%`, @@ -1093,9 +1109,9 @@ const mod = { maxCount: 1, count: 0, allowed() { - return true + return !mod.isBayesian }, - requires: "", + requires: "not Bayesian inference", effect() { mod.isAmmoForGun = true; }, @@ -1127,9 +1143,9 @@ const mod = { maxCount: 1, count: 0, allowed() { - return !mod.isEnergyHealth + return !mod.isEnergyHealth && !mod.isBayesian }, - requires: "not mass-energy equivalence", + requires: "not mass-energy equivalence
not Bayesian inference", effect: () => { mod.isAmmoFromHealth = 0.023; }, @@ -1288,7 +1304,7 @@ const mod = { }, requires: "more than 6 mods", effect: () => { - //remove bullets //to get rid of bots + //remove active bullets //to get rid of bots for (let i = 0; i < bullet.length; ++i) Matter.World.remove(engine.world, bullet[i]); bullet = []; @@ -1324,13 +1340,13 @@ const mod = { if (mod.mods[i].count > 0) have.push(i) } const choose = have[Math.floor(Math.random() * have.length)] + game.makeTextLog(`
  ${mod.mods[choose].name} removed by reallocation`, 300) + for (let i = 0; i < 2 * mod.mods[choose].count; i++) { + powerUps.spawn(mech.pos.x, mech.pos.y, "gun"); + } mod.mods[choose].remove(); // remove a random mod form the list of mods you have mod.mods[choose].count = 0; game.updateModHUD(); - - for (let i = 0; i < 2; i++) { - powerUps.spawn(mech.pos.x, mech.pos.y, "gun"); - } }, remove() {} }, @@ -2155,13 +2171,13 @@ const mod = { requires: "laser", effect() { mod.laserReflections++; - mod.laserDamage += 0.05; //base is 0.1 - mod.laserFieldDrain += 0.001 //base is 0.002 + mod.laserDamage += 0.065; //base is 0.11 + mod.laserFieldDrain += 0.0009 //base is 0.002 }, remove() { mod.laserReflections = 2; - mod.laserDamage = 0.1; - mod.laserFieldDrain = 0.002; + mod.laserDamage = 0.13; + mod.laserFieldDrain = 0.0018; } }, { @@ -2717,5 +2733,6 @@ const mod = { isBayesian: null, nailGun: null, nailInstantFireRate: null, - isCapacitor: null + isCapacitor: null, + isEjectMod: null } \ No newline at end of file diff --git a/js/player.js b/js/player.js index 5dc390a..3e41802 100644 --- a/js/player.js +++ b/js/player.js @@ -359,9 +359,31 @@ const mech = { game.makeGunHUD(); //update gun HUD } + + function pixelWindows() { + + //pixel graphics + let imgData = ctx.getImageData(0, 0, canvas.width, canvas.height); //copy current canvas pixel data + let data = imgData.data; + //change random pixels + //strange draw offset + // const off = canvas.height * canvas.width * 4 / 16 + for (let i = 0; i < data.length; i += 4) { + index = i % canvas.width + data[index + 0] = data[index + 0]; // red + data[index + 1] = data[index + 1]; // red + data[index + 2] = data[index + 2]; // red + data[index + 3] = data[index + 3]; // red + } + ctx.putImageData(imgData, 0, 0); //draw new pixel data to canvas + + } + + game.wipe = function () { //set wipe to have trails ctx.fillStyle = "rgba(255,255,255,0)"; ctx.fillRect(0, 0, canvas.width, canvas.height); + // pixelWindows() } function randomizeEverything() { @@ -387,6 +409,7 @@ const mech = { game.wipe = function () { //set wipe to have trails ctx.fillStyle = `rgba(255,255,255,${(i+1)*(i+1)*0.006})`; ctx.fillRect(0, 0, canvas.width, canvas.height); + // pixelWindows() } }, (i + 1) * swapPeriod); } @@ -450,6 +473,7 @@ const mech = { let dmg = 1 dmg *= mech.fieldHarmReduction dmg *= mod.isSlowFPS ? 0.85 : 1 + if (mod.isEjectMod) dmg *= 0.2 if (mod.isHarmReduce && mech.fieldUpgrades[mech.fieldMode].name === "negative mass field" && mech.isFieldActive) dmg *= 0.6 if (mod.isBotArmor) dmg *= 0.95 ** mod.totalBots() if (mod.isHarmArmor && mech.lastHarmCycle + 600 > mech.cycle) dmg *= 0.5; @@ -691,6 +715,7 @@ const mech = { holdingTarget: null, timeSkipLastCycle: 0, // these values are set on reset by setHoldDefaults() + grabPowerUpRange2: 0, isFieldActive: false, fieldRange: 155, fieldShieldingScale: 1, @@ -713,6 +738,7 @@ const mech = { mech.fieldBlockCD = 10; game.isBodyDamage = true; mech.fieldHarmReduction = 1; + mech.grabPowerUpRange2 = 156000; mech.fieldRange = 155; mech.fieldFire = false; mech.fieldCDcycle = 0; @@ -939,15 +965,18 @@ const mech = { ctx.stroke(); }, grabPowerUp() { //look for power ups to grab with field - const grabPowerUpRange2 = 156000 //(mech.fieldRange + 220) * (mech.fieldRange + 220) for (let i = 0, len = powerUp.length; i < len; ++i) { const dxP = mech.pos.x - powerUp[i].position.x; const dyP = mech.pos.y - powerUp[i].position.y; const dist2 = dxP * dxP + dyP * dyP; // float towards player if looking at and in range or if very close to player - if (dist2 < grabPowerUpRange2 && (mech.lookingAt(powerUp[i]) || dist2 < 16000) && !(mech.health === mech.maxHealth && powerUp[i].name === "heal")) { - powerUp[i].force.x += 7 * (dxP / dist2) * powerUp[i].mass; - powerUp[i].force.y += 7 * (dyP / dist2) * powerUp[i].mass - powerUp[i].mass * game.g; //negate gravity + if (dist2 < mech.grabPowerUpRange2 && + (mech.lookingAt(powerUp[i]) || dist2 < 16000) && + !(mech.health === mech.maxHealth && powerUp[i].name === "heal") && + Matter.Query.ray(map, powerUp[i].position, mech.pos).length === 0 + ) { + powerUp[i].force.x += 0.05 * (dxP / Math.sqrt(dist2)) * powerUp[i].mass; + powerUp[i].force.y += 0.05 * (dyP / Math.sqrt(dist2)) * powerUp[i].mass - powerUp[i].mass * game.g; //negate gravity //extra friction Matter.Body.setVelocity(powerUp[i], { x: powerUp[i].velocity.x * 0.11, @@ -1186,7 +1215,7 @@ const mech = { }, fieldUpgrades: [{ name: "field emitter", - description: "use energy to shield yourself from harm
pick up and throw objects", + description: "use energy to push mobs away
throw blocks to damage mobs
pick up power ups", effect: () => { game.replaceTextLog = true; //allow text over write mech.hold = function () { @@ -1212,9 +1241,9 @@ const mech = { }, { name: "standing wave harmonics", - description: "three oscillating shields are permanently active
reduce harm by 30%", + description: "three oscillating shields are permanently active
blocking has no cool down
reduce harm by 20%", effect: () => { - mech.fieldHarmReduction = 0.70; + mech.fieldHarmReduction = 0.20; mech.fieldBlockCD = 0; mech.hold = function () { if (mech.isHolding) { @@ -1231,8 +1260,8 @@ const mech = { } if (mech.energy > 0.1 && mech.fieldCDcycle < mech.cycle) { const fieldRange1 = (0.7 + 0.3 * Math.sin(mech.cycle / 23)) * mech.fieldRange - const fieldRange2 = (0.6 + 0.4 * Math.sin(mech.cycle / 37)) * mech.fieldRange - const fieldRange3 = (0.55 + 0.45 * Math.sin(mech.cycle / 47)) * mech.fieldRange + const fieldRange2 = (0.63 + 0.37 * Math.sin(mech.cycle / 37)) * mech.fieldRange + const fieldRange3 = (0.65 + 0.35 * Math.sin(mech.cycle / 47)) * mech.fieldRange const netfieldRange = Math.max(fieldRange1, fieldRange2, fieldRange3) ctx.fillStyle = "rgba(110,170,200," + (0.04 + mech.energy * (0.12 + 0.13 * Math.random())) + ")"; ctx.beginPath(); @@ -1254,16 +1283,18 @@ const mech = { { name: "perfect diamagnetism", // description: "gain energy when blocking
no recoil when blocking", - description: "blocking does not drain energy
blocking has no cool down and less recoil", + description: "blocking does not drain energy
blocking has no cool down and less recoil
attract power ups from far away", effect: () => { mech.fieldShieldingScale = 0; + mech.grabPowerUpRange2 = 4000000 + // mech.holdingMassScale = 0.03; //can hold heavier blocks with lower cost to jumping // mech.fieldMeterColor = "#0af" // mech.fieldArc = 0.3; //run calculateFieldThreshold after setting fieldArc, used for powerUp grab and mobPush with lookingAt(mob) // mech.calculateFieldThreshold(); mech.hold = function () { const wave = Math.sin(mech.cycle * 0.022); - mech.fieldRange = 165 + 12 * wave - mech.fieldArc = 0.3 + 0.035 * wave //run calculateFieldThreshold after setting fieldArc, used for powerUp grab and mobPush with lookingAt(mob) + mech.fieldRange = 170 + 12 * wave + mech.fieldArc = 0.33 + 0.045 * wave //run calculateFieldThreshold after setting fieldArc, used for powerUp grab and mobPush with lookingAt(mob) mech.calculateFieldThreshold(); if (mech.isHolding) { mech.drawHold(mech.holdingTarget); @@ -1317,13 +1348,13 @@ const mech = { if (mod.isSporeField) { // mech.fieldCDcycle = mech.cycle + 10; // set cool down to prevent +energy from making huge numbers of drones const len = Math.floor(6 + 4 * Math.random()) - mech.energy -= len * 0.074; + mech.energy -= len * 0.07; for (let i = 0; i < len; i++) { b.spore(mech.pos) } } else if (mod.isMissileField) { // mech.fieldCDcycle = mech.cycle + 10; // set cool down to prevent +energy from making huge numbers of drones - mech.energy -= 0.6; + mech.energy -= 0.55; b.missile({ x: mech.pos.x + 40 * Math.cos(mech.angle), y: mech.pos.y + 40 * Math.sin(mech.angle) - 3 @@ -1333,11 +1364,11 @@ const mech = { 1, mod.babyMissiles) } else if (mod.isIceField) { // mech.fieldCDcycle = mech.cycle + 17; // set cool down to prevent +energy from making huge numbers of drones - mech.energy -= 0.045; + mech.energy -= 0.04; b.iceIX(1) } else { // mech.fieldCDcycle = mech.cycle + 10; // set cool down to prevent +energy from making huge numbers of drones - mech.energy -= 0.33; + mech.energy -= 0.3; b.drone(1) } @@ -1365,13 +1396,15 @@ const mech = { }, { name: "negative mass field", - description: "use energy to nullify   gravity
reduce harm by 45%", + description: "use energy to nullify   gravity
reduce harm by 45%
blocks held by the field have a lower mass", fieldDrawRadius: 0, effect: () => { mech.fieldFire = true; mech.holdingMassScale = 0.03; //can hold heavier blocks with lower cost to jumping mech.fieldMeterColor = "#000" mech.fieldHarmReduction = 0.55; + mech.fieldDrawRadius = 0; + mech.hold = function () { mech.airSpeedLimit = 125 //5 * player.mass * player.mass mech.FxAir = 0.016 @@ -1483,7 +1516,7 @@ const mech = { }, { name: "plasma torch", - description: "use energy to emit short range plasma
plasma damages and pushes mobs", + description: "use energy to emit short range plasma
plasma damages mobs
plasma pushes mobs and blocks away", effect() { mech.fieldMeterColor = "#f0f" mech.hold = function () { @@ -1638,7 +1671,7 @@ const mech = { }, { name: "time dilation field", - description: "use energy to stop time
you can move and fire while time is stopped", + description: "use energy to stop time
move and fire while time is stopped
touching mobs still does harm", effect: () => { // mech.fieldMeterColor = "#000" mech.fieldFire = true; @@ -1667,6 +1700,7 @@ const mech = { ctx.fillStyle = "#ccc"; ctx.fillRect(-100000, -100000, 200000, 200000) ctx.globalCompositeOperation = "source-over" + //stop time mech.isBodiesAsleep = true; @@ -1730,7 +1764,7 @@ const mech = { }, { name: "phase decoherence field", - description: "use energy to become intangible
firing and touching shields increases drain", + description: "use energy to become intangible
firing and touching shields drains energy
unable to see and be seen by mobs", effect: () => { mech.fieldFire = true; mech.fieldMeterColor = "#fff"; diff --git a/js/powerup.js b/js/powerup.js index 77fe4fb..aaa631f 100644 --- a/js/powerup.js +++ b/js/powerup.js @@ -21,24 +21,30 @@ const powerUps = { } powerUps.endDraft(); }, - endDraft() { - if (mod.manyWorlds && powerUps.reroll.rerolls < 1) { - powerUps.spawn(mech.pos.x, mech.pos.y, "reroll"); - } - document.body.style.cursor = "none"; - document.getElementById("choose-grid").style.display = "none" - document.getElementById("choose-background").style.display = "none" - game.paused = false; - game.isChoosing = false; //stops p from un pausing on key down - requestAnimationFrame(cycle); - }, showDraft() { document.getElementById("choose-grid").style.display = "grid" document.getElementById("choose-background").style.display = "inline" document.body.style.cursor = "auto"; + if (mod.isExtraChoice) { + document.body.style.overflowY = "scroll"; + document.body.style.overflowX = "hidden"; + } game.paused = true; game.isChoosing = true; //stops p from un pausing on key down }, + endDraft() { + if (mod.manyWorlds && powerUps.reroll.rerolls < 1) { + powerUps.spawn(mech.pos.x, mech.pos.y, "reroll"); + } + document.getElementById("choose-grid").style.display = "none" + document.getElementById("choose-background").style.display = "none" + document.body.style.cursor = "none"; + document.body.style.overflow = "hidden" + game.paused = false; + game.isChoosing = false; //stops p from un pausing on key down + mech.immuneCycle = mech.cycle + 60; //player is immune to collision damage for 30 cycles + requestAnimationFrame(cycle); + }, reroll: { rerolls: 0, name: "reroll", @@ -48,7 +54,7 @@ const powerUps = { }, effect() { powerUps.reroll.changeRerolls(1) - game.makeTextLog("
  +1 reroll", 300) + game.makeTextLog(`
  rerolls: ${powerUps.reroll.rerolls}`, 300) }, changeRerolls(amount) { powerUps.reroll.rerolls += amount @@ -262,66 +268,67 @@ const powerUps = { }, choiceLog: [], //records all previous choice options effect() { - - function pick(skip1 = -1, skip2 = -1, skip3 = -1, skip4 = -1) { - let options = []; - for (let i = 0; i < mod.mods.length; i++) { - if (mod.mods[i].count < mod.mods[i].maxCount && i !== skip1 && i !== skip2 && i !== skip3 && i !== skip4 && mod.mods[i].allowed()) { - options.push(i); + if (mech.alive) { + function pick(skip1 = -1, skip2 = -1, skip3 = -1, skip4 = -1) { + let options = []; + for (let i = 0; i < mod.mods.length; i++) { + if (mod.mods[i].count < mod.mods[i].maxCount && i !== skip1 && i !== skip2 && i !== skip3 && i !== skip4 && mod.mods[i].allowed()) { + options.push(i); + } } - } - //remove repeats from last selection - const totalChoices = mod.isDeterminism ? 1 : 3 + mod.isExtraChoice * 2 - if (powerUps.mod.choiceLog.length > totalChoices || powerUps.mod.choiceLog.length === totalChoices) { //make sure this isn't the first time getting a power up and there are previous choices to remove - for (let i = 0; i < totalChoices; i++) { //repeat for each choice from the last selection - if (options.length > totalChoices) { - for (let j = 0, len = options.length; j < len; j++) { - if (powerUps.mod.choiceLog[powerUps.mod.choiceLog.length - 1 - i] === options[j]) { - options.splice(j, 1) //remove previous choice from option pool - break + //remove repeats from last selection + const totalChoices = mod.isDeterminism ? 1 : 3 + mod.isExtraChoice * 2 + if (powerUps.mod.choiceLog.length > totalChoices || powerUps.mod.choiceLog.length === totalChoices) { //make sure this isn't the first time getting a power up and there are previous choices to remove + for (let i = 0; i < totalChoices; i++) { //repeat for each choice from the last selection + if (options.length > totalChoices) { + for (let j = 0, len = options.length; j < len; j++) { + if (powerUps.mod.choiceLog[powerUps.mod.choiceLog.length - 1 - i] === options[j]) { + options.splice(j, 1) //remove previous choice from option pool + break + } } } } } - } - if (options.length > 0) { - const choose = options[Math.floor(Math.random() * options.length)] - text += `
  ${mod.mods[choose].name}
${mod.mods[choose].description}
` - return choose - } + if (options.length > 0) { + const choose = options[Math.floor(Math.random() * options.length)] + text += `
  ${mod.mods[choose].name}
${mod.mods[choose].description}
` + return choose + } - } - let text = "" - if (!mod.isDeterminism) text += `
` - text += `

choose a mod

` - let choice1 = pick() - let choice2 = -1 - let choice3 = -1 - if (choice1 > -1) { - if (!mod.isDeterminism) { - choice2 = pick(choice1) - // if (choice2 > -1) text += `
  ${mod.mods[choice2].name}
${mod.mods[choice2].description}
` - choice3 = pick(choice1, choice2) - // if (choice3 > -1) text += `
  ${mod.mods[choice3].name}
${mod.mods[choice3].description}
` } - if (mod.isExtraChoice) { - let choice4 = pick(choice1, choice2, choice3) - // if (choice4 > -1) text += `
  ${mod.mods[choice4].name}
${mod.mods[choice4].description}
` - let choice5 = pick(choice1, choice2, choice3, choice4) - // if (choice5 > -1) text += `
  ${mod.mods[choice5].name}
${mod.mods[choice5].description}
` - powerUps.mod.choiceLog.push(choice4) - powerUps.mod.choiceLog.push(choice5) - } - powerUps.mod.choiceLog.push(choice1) - powerUps.mod.choiceLog.push(choice2) - powerUps.mod.choiceLog.push(choice3) - if (powerUps.reroll.rerolls) text += `
  reroll ${powerUps.reroll.diceText()}
` + let text = "" + if (!mod.isDeterminism) text += `
` + text += `

choose a mod

` + let choice1 = pick() + let choice2 = -1 + let choice3 = -1 + if (choice1 > -1) { + if (!mod.isDeterminism) { + choice2 = pick(choice1) + // if (choice2 > -1) text += `
  ${mod.mods[choice2].name}
${mod.mods[choice2].description}
` + choice3 = pick(choice1, choice2) + // if (choice3 > -1) text += `
  ${mod.mods[choice3].name}
${mod.mods[choice3].description}
` + } + if (mod.isExtraChoice) { + let choice4 = pick(choice1, choice2, choice3) + // if (choice4 > -1) text += `
  ${mod.mods[choice4].name}
${mod.mods[choice4].description}
` + let choice5 = pick(choice1, choice2, choice3, choice4) + // if (choice5 > -1) text += `
  ${mod.mods[choice5].name}
${mod.mods[choice5].description}
` + powerUps.mod.choiceLog.push(choice4) + powerUps.mod.choiceLog.push(choice5) + } + powerUps.mod.choiceLog.push(choice1) + powerUps.mod.choiceLog.push(choice2) + powerUps.mod.choiceLog.push(choice3) + if (powerUps.reroll.rerolls) text += `
  reroll ${powerUps.reroll.diceText()}
` - document.getElementById("choose-grid").innerHTML = text - powerUps.showDraft(); - } else { - powerUps.giveRandomAmmo() + document.getElementById("choose-grid").innerHTML = text + powerUps.showDraft(); + } else { + powerUps.giveRandomAmmo() + } } } }, @@ -449,11 +456,7 @@ const powerUps = { randomPowerUpCounter: 0, spawnBossPowerUp(x, y) { //boss spawns field and gun mod upgrades powerUps.randomPowerUpCounter++; - if (game.difficultyMode === 4 && Math.random() < 0.5) { //why mode gets a free power up chance - powerUps.randomPowerUpCounter *= 0.5 - spawnPowerUps() - } - + if (game.difficultyMode === 4) spawnPowerUps() //why mode gets a free power up chance const chanceToFail = Math.max(level.levelsCleared, 10) * 0.1 //1 until level 10, then 1.1, 1.2, 1.3, ... if (Math.random() * chanceToFail < powerUps.randomPowerUpCounter) { powerUps.randomPowerUpCounter = 0; @@ -528,8 +531,8 @@ const powerUps = { size = target.size(); powerUp[index] = Matter.Bodies.polygon(x, y, 0, size, { density: 0.001, - frictionAir: 0.01, - restitution: 0.8, + frictionAir: 0.03, + restitution: 0.85, inertia: Infinity, //prevents rotation collisionFilter: { group: 0, diff --git a/todo.txt b/todo.txt index 6b83634..5cf6c2c 100644 --- a/todo.txt +++ b/todo.txt @@ -1,43 +1,46 @@ -rail gun mod: capacitor bank - no charge time, but smaller bullets +field: perfect diamagnetism is a bit larger + can now grab power ups from far away -stunned mobs now still display health bar -when you hit a mob hard with a block they get stunned - blocks do about 15% less collision damage - stuns lasts longer for larger and faster blocks - +mod: exciton-lattice - reduce harm by 80%, but after taking collision damage eject a random mod + eject extra mods if you have recursive stacks + +power ups have a bit more air friction +power ups must be in line of sight to be pulled by the player +why mode now gets 100% chance for a second boss power up (up from 50%) + this should let why mode reach more interesting build depth +laser and pulse got a damage and energy use buff +immune to harm for a second after exiting the power up selection menu ************** TODO - n-gon ************** -player goes intangible while immune after getting hit? -getting stuck above a mob can immobilize player - add a minimum knock from player mob collisions? +new gun fire 3+ balls in arc + name: something about energy + does damage in area, like neutron bomb + ends on contact with wall, doesn't stick or bounce + hold fire to charge: increases the size of the balls + mod: balls are attracted to mobs -when crouched make it harder for mobs to see player - reduce arc size of mob vision cone - reduce look range - * (mech.crouch ? 0.7 : 1) +fix: even with a scroll bar the top of the selection window is off screen for very short windows + +rework perfect diamagnetism + keep the zero energy cost + add a very short blocking CD + let the shield also do bremsstrahlung radiation + mod: grab and launch mobs? + +getting stuck above a mob can immobilize player + seems to only occur with Pauli exclusion + add a knock to player mob collisions even while player is immune to damage + keep the knock very small map element - player rotates a rotor that makes a platform go up or down -reduce damage by 80%, but lose ammo when you get hit - -foam needs a new mod - is the foam mod colloidal foam fun? - increase foam bullet size? - foam explodes when it runs out? - removing supersaturation sets total health to 1 this cancels the health benefits from crystallized armor produce a method that calculates max health based on mods use mac automator to speed up your n-gon -> git sync -considering removing the perfect diamagnetism field from the game - or just rework perfect diamagnetism - perfect diamagnetism be able to grab and launch mobs - -Gun: Launch yourself at high speed to the enemy, gaining temporary invincibility while in the air and for 3 seconds after landing. Upon impact, trigger a large explosion. - fix door.isOpen actually meaning isClosed mod - laser fires 3 beams @@ -45,27 +48,18 @@ mod - laser fires 3 beams after you die custom should be populated with your last build also you should be able to share while paused -use canvas pixel array effects for full screen graphics - add some pixels after player gets hit? - give missiles a suck and delay explosion, like vacuum bomb bot that does AOE damage while it rotates around player no physics / collisions cap 3 ? - level Boss: fractal Sierpiński triangle https://en.wikipedia.org/wiki/Sierpi%C5%84ski_triangle spawns a 1/2 size version of the boss, this version can also spawn a smaller version, but it is capped at some size level they spawn once at the start of the level if a version dies, one can be replaced every ten seconds by the largest version -performance issues with large numbers of spores -consider limiting total bullets? - 300? - -level element: a hanging chain of connected blocks level element: a zone with wind, anti-gravity, extra gravity control with button @@ -123,15 +117,6 @@ new gun - deploy a turret that last for 20 seconds mod - mines become a turret that fires nails it could float to the mouse location on fire -minigun: high caliber - rework - slow down the bullets even more and increase the size? - remove and actually make a full gun like this? - -portals: - portal while holding block sometimes send player back to original portal - only seems to happen with the bottom right block - use buttons to turn on and off? - level boss: fires a line intersection in a random direction every few seconds. the last two intersections have a destructive laser between them. @@ -144,8 +129,6 @@ map: prison doors linked to buttons mobs inside the doors? -map: airport - mod - do 50% more damage in close, but 50% less at a distance code it like mod.isFarAwayDmg have these mods disable each other @@ -153,9 +136,6 @@ mod - do 50% more damage in close, but 50% less at a distance phase field still isn't fun does phase field need the stealth flag? -mod: use the stealth flag from the phase decoherence field - maybe trigger it along with the damage immunity CD - mod harmonic shield: slow everything in range around shield (temporal shield) set max speed? @@ -166,10 +146,6 @@ mod: bot very slowly follows you and gives you a bonus when it's in range graphic idea: bezier curve that moves smoothly from mob to mob loops around player -graphic: give rail gun projectile a trail - only draw above speed 5 - track previous positions? - movement fluidity let legs jump on mobs, but player will still take damage like: ori and the blind forest, celeste