From dde4432279d56e957a2193a156b53a77ba6c2a61 Mon Sep 17 00:00:00 2001 From: landgreen Date: Sun, 20 Mar 2022 15:43:51 -0700 Subject: [PATCH] plasma ball plasma ball is now live, but it's still in beta still needs new graphics damage balancing fast decay in mob shields player angle rotation speed while firing adds to fire speed tech upgrade to get electrical arcs that randomly damage nearby mobs current tech synergy capacitor bank,plasma jet(range?) reservoir level is less crowded, so you can dodge mobs easier horizontal flipped version is so reenabled pure science renamed paradigm shift difficulty scaling for heal and mob damage reduced 2% some possible bug fixes, I don't know... --- .DS_Store | Bin 6148 -> 6148 bytes js/bullet.js | 164 ++++++++++++++++++++++++++++++++++++++++++++++- js/engine.js | 2 +- js/index.js | 4 +- js/level.js | 97 ++++++++++++++++------------ js/player.js | 127 ++++++++++++++++++++++++++++++++++-- js/simulation.js | 4 +- js/spawn.js | 2 +- js/tech.js | 155 +++++++++++++++++++++++++------------------- style.css | 2 +- todo.txt | 72 +++++++++++++++------ 11 files changed, 489 insertions(+), 140 deletions(-) diff --git a/.DS_Store b/.DS_Store index 4469fa6af600b88534581c214eca5ca767beec9a..a18c0cc15762a2bf5c8a62d728d0832a33f9929c 100644 GIT binary patch delta 22 dcmZoMXffEJ#mw}eZL$utFO%Yd&DG4EA^=x#2W|iW delta 22 dcmZoMXffEJ#mqEg{$w3yUnYeQo2!{SMF3Ua2W|iW diff --git a/js/bullet.js b/js/bullet.js index ded5cbb..add0550 100644 --- a/js/bullet.js +++ b/js/bullet.js @@ -1519,6 +1519,7 @@ const b = { if (input.fire && Matter.Query.collides(this, map).length) { Matter.Body.setPosition(this, Vector.add(this.position, { x: 20 * Math.cos(this.angle), y: 20 * Math.sin(this.angle) })) if (Matter.Query.collides(this, map).length) { + Matter.Body.setVelocity(this, { x: 0, y: 0 }); Matter.Sleeping.set(this, true) this.endCycle = simulation.cycle + 5 this.dropCaughtPowerUp() @@ -2605,7 +2606,7 @@ const b = { }, worm(where, isFreeze = tech.isSporeFreeze) { //used with the tech upgrade in mob.death() const bIndex = bullet.length; - const wormSize = 6 + tech.wormSize * 7.2 * Math.random() + const wormSize = 6 + tech.wormSize * 7 * Math.random() if (bIndex < 500) { //can't make over 500 spores bullet[bIndex] = Bodies.polygon(where.x, where.y, 3, 3, { inertia: Infinity, @@ -2616,7 +2617,7 @@ const b = { frictionAir: 0.025, thrust: (tech.isFastSpores ? 0.001 : 0.0005) * (1 + 0.5 * (Math.random() - 0.5)), wormSize: wormSize, - wormTail: 1 + wormSize, + wormTail: 1 + Math.max(4, wormSize - 2 * tech.wormSize), dmg: (tech.isMutualism ? 7 : 2.9) * wormSize, //bonus damage from tech.isMutualism //2.5 is extra damage as worm lookFrequency: 100 + Math.floor(37 * Math.random()), classType: "bullet", @@ -3329,6 +3330,165 @@ const b = { y: speed * Math.sin(dir) }); }, + // plasmaBall(position, velocity, radius) { + // // radius *= Math.sqrt(tech.bulletSize) + // const me = bullet.length; + // bullet[me] = Bodies.polygon(position.x, position.y, 20, radius, { + // density: 0.000001, // 0.001 is normal density + // inertia: Infinity, + // frictionAir: 0.003, + // dmg: 0, //damage on impact + // damage: 0, //damage done over time + // scale: 1 - 0.006 / tech.isBulletsLastLonger, + // classType: "bullet", + // collisionFilter: { + // category: cat.bullet, + // mask: 0 //cat.mob | cat.mobBullet // cat.map | cat.body | cat.mob | cat.mobShield + // }, + // minDmgSpeed: 0, + // endCycle: Infinity, + // count: 0, + // radius: radius, + // portFrequency: 5 + Math.floor(5 * Math.random()), + // nextPortCycle: Infinity, //disabled unless you have the teleport tech + // beforeDmg(who) { + // if (!this.target && who.alive) { + // this.target = who; + // if (who.radius < 20) { + // this.targetRelativePosition = { + // x: 0, + // y: 0 + // } //find relative position vector for zero mob rotation + // } else if (Matter.Query.collides(this, [who]).length > 0) { + // const normal = Matter.Query.collides(this, [who])[0].normal + // this.targetRelativePosition = Vector.rotate(Vector.sub(Vector.sub(this.position, who.position), Vector.mult(normal, -this.radius)), -who.angle) //find relative position vector for zero mob rotation + // } else { + // this.targetRelativePosition = Vector.rotate(Vector.sub(this.position, who.position), -who.angle) //find relative position vector for zero mob rotation + // } + // this.collisionFilter.category = cat.body; + // this.collisionFilter.mask = null; + + // let bestVertexDistance = Infinity + // let bestVertex = null + // for (let i = 0; i < this.target.vertices.length; i++) { + // const dist = Vector.magnitude(Vector.sub(this.position, this.target.vertices[i])); + // if (dist < bestVertexDistance) { + // bestVertex = i + // bestVertexDistance = dist + // } + // } + // this.targetVertex = bestVertex + // } + // }, + // onEnd() {}, + // do() { + // if (this.count < 20) { + // this.count++ + // //grow + // const SCALE = 1.06 + // Matter.Body.scale(this, SCALE, SCALE); + // this.radius *= SCALE; + // } else { + // //shrink + // Matter.Body.scale(this, this.scale, this.scale); + // this.radius *= this.scale; + // if (this.radius < 8) this.endCycle = 0; + // } + // if (this.target && this.target.alive) { //if stuck to a target + // const rotate = Vector.rotate(this.targetRelativePosition, this.target.angle) //add in the mob's new angle to the relative position vector + // if (this.target.isVerticesChange) { + // Matter.Body.setPosition(this, this.target.vertices[this.targetVertex]) + // } else { + // Matter.Body.setPosition(this, Vector.add(Vector.add(rotate, this.target.velocity), this.target.position)) + // } + // if (this.target.isBoss) { + // if (this.target.speed > 8) Matter.Body.setVelocity(this.target, Vector.mult(this.target.velocity, 0.98)) + // } else { + // if (this.target.speed > 4) Matter.Body.setVelocity(this.target, Vector.mult(this.target.velocity, 0.95)) + // } + + // Matter.Body.setAngularVelocity(this.target, this.target.angularVelocity * 0.9); + // // Matter.Body.setAngularVelocity(this.target, this.target.angularVelocity * 0.9) + // if (this.target.isShielded) { + // this.target.damage(m.dmgScale * this.damage, true); //shield damage bypass + // const SCALE = 1 - 0.004 / tech.isBulletsLastLonger //shrink if mob is shielded + // Matter.Body.scale(this, SCALE, SCALE); + // this.radius *= SCALE; + // } else { + // this.target.damage(m.dmgScale * this.damage); + // } + // } else if (this.target !== null) { //look for a new target + // this.collisionFilter.category = cat.bullet; + // this.collisionFilter.mask = cat.mob //| cat.mobShield //cat.map | cat.body | cat.mob | cat.mobBullet | cat.mobShield + // if (tech.isSpawnBulletsOnDeath && bullet.length < 180 && !this.target.isMobBullet) { + // let targets = [] + // for (let i = 0, len = mob.length; i < len; i++) { + // const dist = Vector.magnitudeSquared(Vector.sub(this.position, mob[i].position)); + // if (dist < 1000000) targets.push(mob[i]) + // } + // const radius = Math.min(this.radius * 0.5, 9) + // const len = bullet.length < 80 ? 2 : 1 + // for (let i = 0; i < len; i++) { + // if (targets.length - i > 0) { + // const index = Math.floor(Math.random() * targets.length) + // const speed = 6 + 6 * Math.random() + // const velocity = Vector.mult(Vector.normalise(Vector.sub(targets[index].position, this.position)), speed) + // b.foam(this.position, Vector.rotate(velocity, 0.5 * (Math.random() - 0.5)), radius) + // } else { + // b.foam(this.position, Vector.rotate({ + // x: 15 + 10 * Math.random(), + // y: 0 + // }, 2 * Math.PI * Math.random()), radius) + // } + // } + // } + // this.target = null + // } else if (Matter.Query.point(map, this.position).length > 0) { //slow when touching map or blocks + // const slow = 0.85 + // Matter.Body.setVelocity(this, { + // x: this.velocity.x * slow, + // y: this.velocity.y * slow + // }); + // const SCALE = 0.96 + // Matter.Body.scale(this, SCALE, SCALE); + // this.radius *= SCALE; + // // } else if (Matter.Query.collides(this, body).length > 0) { + // } else if (Matter.Query.point(body, this.position).length > 0) { + // const slow = 0.9 + // Matter.Body.setVelocity(this, { + // x: this.velocity.x * slow, + // y: this.velocity.y * slow + // }); + // const SCALE = 0.96 + // Matter.Body.scale(this, SCALE, SCALE); + // this.radius *= SCALE; + // } else { + // this.force.y += this.mass * tech.foamGravity; //gravity + // if (tech.isFoamAttract) { + // for (let i = 0, len = mob.length; i < len; i++) { + // if (!mob[i].isBadTarget && Vector.magnitude(Vector.sub(mob[i].position, this.position)) < 375 && mob[i].alive && Matter.Query.ray(map, this.position, mob[i].position).length === 0) { + // this.force = Vector.mult(Vector.normalise(Vector.sub(mob[i].position, this.position)), this.mass * 0.004) + // const slow = 0.9 + // Matter.Body.setVelocity(this, { + // x: this.velocity.x * slow, + // y: this.velocity.y * slow + // }); + // break + // } + // } + // } + // } + // if (this.nextPortCycle < simulation.cycle) { //teleport around if you have tech.isBulletTeleport + // this.nextPortCycle = simulation.cycle + this.portFrequency + // const range = 15 * Math.sqrt(this.radius) * Math.random() + // Matter.Body.setPosition(this, Vector.add(this.position, Vector.rotate({ x: range, y: 0 }, 2 * Math.PI * Math.random()))) + // } + // } + // }); + // if (tech.isBulletTeleport) bullet[me].nextPortCycle = simulation.cycle + bullet[me].portFrequency + // Composite.add(engine.world, bullet[me]); //add bullet to world + // Matter.Body.setVelocity(bullet[me], velocity); + // }, foam(position, velocity, radius) { // radius *= Math.sqrt(tech.bulletSize) const me = bullet.length; diff --git a/js/engine.js b/js/engine.js index 7a5490c..d63bb82 100644 --- a/js/engine.js +++ b/js/engine.js @@ -188,7 +188,7 @@ function collisionChecks(event) { time: simulation.drawTime }); } - if (tech.isLessDamageReduction && !mob[k].shield) mob[k].damageReduction *= mob[k].isBoss ? 1.01 : 1.06 + if (tech.isLessDamageReduction && !mob[k].shield) mob[k].damageReduction *= mob[k].isBoss ? 1.005 : 1.05 return; } //mob + body collisions diff --git a/js/index.js b/js/index.js index 071c08b..4be212f 100644 --- a/js/index.js +++ b/js/index.js @@ -326,7 +326,7 @@ ${simulation.isCheating ? "

lore disabled": ""}         ${tech.tech[i].link} ${techCountText}${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}` } else if (tech.tech[i].isLore) { - text += `
  ${tech.tech[i].name} ${techCountText}
${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}
` + text += `
  ${tech.tech[i].name} ${techCountText}
${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}
` } else { text += `
  ${tech.tech[i].link} ${techCountText}
${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}
` } @@ -379,7 +379,7 @@ ${simulation.isCheating ? "

lore disabled": ""} if (!who.classList.contains("build-tech-selected")) who.classList.add("build-tech-selected"); tech.giveTech(index) } else if (!tech.tech[index].isNonRefundable) { - tech.totalCount -= tech.tech[index].count + // tech.totalCount -= tech.tech[index].count tech.removeTech(index); who.classList.remove("build-tech-selected"); } else { diff --git a/js/level.js b/js/level.js index 38f2131..da8a2f1 100644 --- a/js/level.js +++ b/js/level.js @@ -15,35 +15,35 @@ const level = { start() { if (level.levelsCleared === 0) { //this code only runs on the first level // simulation.isHorizontalFlipped = true - // m.setField("molecular assembler") - // b.giveGuns("drones") - // tech.giveTech("autonomous navigation") - // tech.giveTech("delivery drone") - // tech.giveTech("dynamo-bot upgrade") + // m.setField("metamaterial cloaking") + // b.giveGuns("harpoon") + // tech.giveTech("grappling hook") + // tech.giveTech("bulk modulus") // for (let i = 0; i < 2; i++) powerUps.directSpawn(0, 0, "tech"); // for (let i = 0; i < 9; i++) tech.giveTech("dynamo-bot") // for (let i = 10; i < tech.tech.length; i++) { tech.tech[i].isBanished = true } // powerUps.research.changeRerolls(100000) - // for (let i = 0; i < 2; i++) tech.giveTech("laser-bot") + // for (let i = 0; i < 2; i++) tech.giveTech("undefined") // tech.tech[297].frequency = 100 + // m.setField("plasma torch") + // tech.giveTech("plasma ball") // m.immuneCycle = Infinity //you can't take damage // level.difficultyIncrease(30) //30 is near max on hard //60 is near max on why // simulation.enableConstructMode() //used to build maps in testing mode // level.reactor(); - // level.testing(); //not in rotation, used for testing - // level.perplex() - if (simulation.isTraining) { level.walk(); } else { level.intro(); } - + // level.pavilion(); //not in rotation, used for testing + if (simulation.isTraining) { level.walk(); } else { level.intro(); } //normal starting level ************************************************ // powerUps.research.changeRerolls(3000) // for (let i = 0; i < 30; i++) powerUps.spawn(player.position.x + Math.random() * 50, player.position.y - Math.random() * 50, "tech", false); // for (let i = 0; i < 3; i++) tech.giveTech("undefined") // lore.techCount = 3 // simulation.isCheating = false //true; - // localSettings.loreCount = 2; //this sets what conversation is heard + // localSettings.loreCount = 0; //this sets what conversation is heard // if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage // level.onLevel = -1 //this sets level.levels[level.onLevel] = undefined which is required to run the conversation // level.null() + // lore.unlockTesting(); // tech.giveTech("tinker"); //show junk tech in experiment mode } else { @@ -113,6 +113,9 @@ const level = { for (let i = 0; i < 2; i++) powerUps.spawn(level.exit.x + 10 * (Math.random() - 0.5), level.exit.y - 100 + 10 * (Math.random() - 0.5), "tech", false) //exit // for (let i = 0; i < 2; i++) powerUps.spawn(player.position.x + 90 * (Math.random() - 0.5), player.position.y + 90 * (Math.random() - 0.5), "tech", false); //start } + if (m.plasmaBall) { + m.plasmaBall.isOn = false + } }, trainingText(say) { simulation.lastLogTime = 0; //clear previous messages @@ -130,7 +133,7 @@ const level = { simulation.accelScale = 1 //mob acceleration increases each level simulation.CDScale = 1 //mob CD time decreases each level simulation.dmgScale = Math.max(0.1, 0.34 * simulation.difficulty) //damage done by mobs scales with total levels - simulation.healScale = 1 / (1 + simulation.difficulty * 0.055) //a higher denominator makes for lower heals // m.health += heal * simulation.healScale; + simulation.healScale = 1 / (1 + simulation.difficulty * 0.052) //a higher denominator makes for lower heals // m.health += heal * simulation.healScale; }, difficultyIncrease(num = 1) { for (let i = 0; i < num; i++) { @@ -140,7 +143,7 @@ const level = { if (simulation.CDScale > 0.15) simulation.CDScale *= 0.965 //mob CD time decreases each level } simulation.dmgScale = Math.max(0.1, 0.34 * simulation.difficulty) //damage done by mobs scales with total levels - simulation.healScale = 1 / (1 + simulation.difficulty * 0.055) //a higher denominator makes for lower heals // m.health += heal * simulation.healScale; + simulation.healScale = 1 / (1 + simulation.difficulty * 0.052) //a higher denominator makes for lower heals // m.health += heal * simulation.healScale; // console.log(`CD = ${simulation.CDScale}`) }, difficultyDecrease(num = 1) { //used in easy mode for simulation.reset() @@ -151,8 +154,8 @@ const level = { if (simulation.CDScale < 1) simulation.CDScale /= 0.965 //mob CD time decreases each level } if (simulation.difficulty < 1) simulation.difficulty = 0; - simulation.dmgScale = Math.max(0.1, 0.35 * simulation.difficulty) //damage done by mobs scales with total levels - simulation.healScale = 1 / (1 + simulation.difficulty * 0.055) + simulation.dmgScale = Math.max(0.1, 0.34 * simulation.difficulty) //damage done by mobs scales with total levels + simulation.healScale = 1 / (1 + simulation.difficulty * 0.052) }, difficultyText() { if (simulation.difficultyMode === 1) { @@ -836,7 +839,7 @@ const level = { // const block = body[body.length] = Bodies.rectangle(x, y, width, height, { collisionFilter: { category: cat.map, - mask: cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet + mask: cat.player | cat.body | cat.bullet | cat.powerUp // | cat.mob | cat.mobBullet }, isNoSetCollision: true, inertia: Infinity, //prevents rotation @@ -3173,9 +3176,12 @@ const level = { //right spawn.mapVertex(425 + 437, -50, "490 0 350 80 -350 80 -490 0 -350 -80 350 -80"); spawn.mapRect(325, -100, 1070, 100); - spawn.mapRect(225, 675, 375, 25); - spawn.mapRect(675, 450, 375, 25); - spawn.mapRect(1125, 225, 375, 25); + // spawn.mapRect(225, 675, 375, 25); + // spawn.mapRect(675, 450, 375, 25); + // spawn.mapRect(1125, 225, 375, 25); + spawn.mapRect(175, 675, 425, 25); + spawn.mapRect(1125, 225, 425, 25); + spawn.mapRect(650, 450, 425, 25); if (Math.random() < 0.33) { spawn.mapVertex(855, -1000, "-100 -300 0 -350 100 -300 100 300 0 350 -100 300"); @@ -3190,12 +3196,19 @@ const level = { spawn.mapVertex(-687, -1936, "-612 50 0 100 612 50 612 -50 -612 -50"); //2nd floor right building - spawn.mapRect(550, -3050, 600, 175); + // spawn.mapRect(550, -3050, 600, 175); + spawn.mapRect(550, -3050, 600, 75); spawn.bodyRect(-125, -2025, 475, 25); //2nd floor left building - spawn.mapRect(-925, -2350, 675, 200); - spawn.mapRect(-825, -2825, 425, 275); + // if (Math.random() > 0.5) { + // spawn.mapRect(-925, -2350, 675, 200); + // } else { + // } + + spawn.mapRect(-925, -2350, 675, 50); + spawn.mapRect(-825, -2825, 425, 50); + // spawn.mapRect(-825, -2825, 425, 275); spawn.mapRect(-450, -3125, 50, 350); spawn.mapRect(-750, -3150, 350, 50); spawn.mapRect(-650, -3400, 250, 300); @@ -3203,8 +3216,11 @@ const level = { spawn.bodyRect(-375, -2150, 100, 150, 0.2); //2nd floor left pillar spawn.mapRect(-1400, -2625, 325, 25); - spawn.mapRect(-1400, -3225, 325, 25); - spawn.mapRect(-1400, -3825, 325, 25); + spawn.mapRect(-1450, -3225, 425, 25); + // spawn.mapRect(-1500, -3825, 525, 25); + spawn.mapRect(-1512.5, -3825, 550, 25); + // spawn.mapRect(-1400, -3225, 325, 25); + // spawn.mapRect(-1400, -3825, 325, 25); spawn.randomMob(1000, -275, 0.2); spawn.randomMob(950, -1725, 0.1); @@ -3231,7 +3247,7 @@ const level = { slime.min.y += slime.maxHeight slime.max.y = slime.min.y + slime.height const elevator1 = level.elevator(-1625, -90, 310, 800, -2000, 0.0025, { up: 0.1, down: 0.2 }) //x, y, width, height, maxHeight, force = 0.003, friction = { up: 0.01, down: 0.2 }) { - const elevator2 = level.elevator(1175, -3050, 200, 300, -4475, 0.0025, { up: 0.12, down: 0.2 }) //x, y, width, height, maxHeight, force = 0.003, friction = { up: 0.01, down: 0.2 }) { + const elevator2 = level.elevator(1175, -3050, 200, 250, -4475, 0.0025, { up: 0.12, down: 0.2 }) //x, y, width, height, maxHeight, force = 0.003, friction = { up: 0.01, down: 0.2 }) { let waterFallWidth = 0 let waterFallX = 0 let waterFallSmoothX = 0 @@ -3242,10 +3258,10 @@ const level = { // level.difficultyIncrease(30) //30 is near max on hard //60 is near max on why // m.immuneCycle = Infinity //you can't take damage - simulation.isHorizontalFlipped = true + // simulation.isHorizontalFlipped = true if (simulation.isHorizontalFlipped) { //flip the map horizontally - spawn.mapVertex(584, -2435, "0 0 300 0 150 600 0 600"); - spawn.mapVertex(1116, -2435, "0 0 300 0 300 600 150 600"); + spawn.mapVertex(584, -2500, "0 0 300 0 150 600 0 600"); + spawn.mapVertex(1116, -2500, "0 0 300 0 300 600 150 600"); spawn.bodyRect(-200, -125, 625, 25); level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit @@ -3255,7 +3271,7 @@ const level = { spinnerArray.push(level.spinner(-110, -3325, 45, 600, 0.003, 0, 0, 0.01)) // spinner(x, y, width, height, density = 0.001, angle = 0, frictionAir = 0.001, angularVelocity = 0) { - const boost1 = level.boost(-900, -2000, 700) + const boost1 = level.boost(-900, -2000, 790) level.setPosToSpawn(500, 850); //normal spawn level.custom = () => { ctx.fillStyle = "#c0c3c9" ///!!!!!!!!!! for flipped x: newX = -oldX - width @@ -3287,11 +3303,11 @@ const level = { ctx.fill(); //shadow ctx.fillStyle = "rgba(0,10,30,0.1)" - ctx.fillRect(-1150, -2900, 600, 925); + ctx.fillRect(-1150, -3000, 600, 1025); ctx.fillRect(450, -3100, 300, 275); ctx.fillRect(450, -3625, 200, 225); - ctx.fillRect(400, -2575, 425, 325); - ctx.fillRect(250, -2150, 675, 150); + ctx.fillRect(400, -2775, 425, 450); + ctx.fillRect(250, -2300, 675, 300); slime.query(); if (isWaterfallFilling) { @@ -3319,6 +3335,8 @@ const level = { } }; } else { //not flipped + spawn.mapVertex(1116, -2500, "0 0 300 0 150 600 0 600"); + spawn.mapVertex(584, -2500, "0 0 300 0 300 600 150 600"); if (Math.random() < 0.33) { spinnerArray.push(level.spinner(65, -300, 40, 450, 0.003, Math.PI / 2)) @@ -3336,7 +3354,7 @@ const level = { Matter.Body.setVertices(spinnerArray[spinnerArray.length - 1].bodyB, Vertices.fromPath(hexagon)) } - const boost1 = level.boost(800, -2000, 700) + const boost1 = level.boost(800, -2000, 790) level.custom = () => { ctx.fillStyle = "#c0c3c9" @@ -3346,7 +3364,6 @@ const level = { ctx.fillStyle = "#d0d4d6" ctx.fillRect(-1100, -1925, 825, 2925) //large pillar background ctx.fillRect(450, -1925, 825, 2925) //large pillar background - ctx.fillStyle = "#cff" //exit ctx.fillRect(1475, -4900, 525, 425) level.exit.drawAndCheck(); @@ -3369,11 +3386,11 @@ const level = { ctx.fill(); //shadow ctx.fillStyle = "rgba(0,10,30,0.1)" - ctx.fillRect(550, -2900, 600, 925); + ctx.fillRect(550, -3000, 600, 1025); ctx.fillRect(-750, -3100, 300, 275); ctx.fillRect(-650, -3625, 200, 225); - ctx.fillRect(-825, -2575, 425, 325); - ctx.fillRect(-925, -2150, 675, 150); + ctx.fillRect(-825, -2775, 425, 450); + ctx.fillRect(-925, -2300, 675, 300); slime.query(); if (isWaterfallFilling) { @@ -6019,10 +6036,10 @@ const level = { const balance = level.spinner(5500, -412.5, 25, 660) //entrance const rotor = level.rotor(7000, 580, -0.001); const doorSortieSalle = level.door(8590, -520, 20, 800, 750) - let buttonSortieSalle - let portalEnBas + // let buttonSortieSalle + // let portalEnBas let portalEnHaut - let door3isClosing = false; + // let door3isClosing = false; function drawOnTheMapMapRect(x, y, dx, dy) { spawn.mapRect(x, y, dx, dy); diff --git a/js/player.js b/js/player.js index 9306255..ca03267 100644 --- a/js/player.js +++ b/js/player.js @@ -34,9 +34,9 @@ const m = { category: cat.player, mask: cat.body | cat.map | cat.mob | cat.mobBullet | cat.mobShield }, - death() { - m.death(); - } + // death() { + // m.death(); + // } }); Matter.Body.setMass(player, m.mass); Composite.add(engine.world, [player]); @@ -2085,7 +2085,126 @@ const m = { description: "use energy to emit short range plasma
damages and pushes mobs away", set() { b.isExtruderOn = false - if (tech.isExtruder) { + if (m.plasmaBall) { + m.plasmaBall.isOn = false + Matter.Composite.remove(engine.world, m.plasmaBall); + } + if (tech.isPlasmaBall) { + // m.plasmaBall = { + // position: { x: m.pos.x + 10 * Math.cos(m.angle), y: m.pos.y + 10 * Math.sin(m.angle) }, + // velocity: { x: 0, y: 0 }, + // radius: 1, + // } + + m.plasmaBall = Bodies.circle(m.pos.x + 10 * Math.cos(m.angle), m.pos.y + 10 * Math.sin(m.angle), 1, { + collisionFilter: { + group: 0, + category: 0, + mask: 0 //cat.body | cat.map | cat.mob | cat.mobBullet | cat.mobShield + }, + frictionAir: 0, + // radius: 1, + // friction: 0, + // frictionStatic: 0, + // restitution: 0, + alpha: 0.6, + isAttached: false, + isOn: false, + drain: 0.0012, + radiusLimit: 10, + damage: 0.18, + setPositionToNose() { + const nose = { x: m.pos.x + 10 * Math.cos(m.angle), y: m.pos.y + 10 * Math.sin(m.angle) } + Matter.Body.setPosition(this, Vector.add(nose, Vector.mult(Vector.normalise(Vector.sub(nose, m.pos)), this.circleRadius))); + }, + fire() { + this.isAttached = false; + const speed = 4 //scale with mass? + Matter.Body.setVelocity(this, { + x: 0.4 * player.velocity.x + speed * Math.cos(m.angle), + y: 0.2 * player.velocity.y + speed * Math.sin(m.angle) + }); + }, + do() { + if (this.isOn) { + //collisions with map + if (Matter.Query.collides(this, map).length > 0) { + const scale = Math.max(0.7, 0.99 - 1 / m.plasmaBall.circleRadius) + Matter.Body.scale(m.plasmaBall, scale, scale); //shrink fast + if (m.plasmaBall.circleRadius < m.plasmaBall.radiusLimit) this.isOn = false + } + //collisions with mobs + const whom = Matter.Query.collides(this, mob) + const dmg = this.damage * m.dmgScale + for (let i = 0, len = whom.length; i < len; i++) { + if (whom[i].bodyA.alive) whom[i].bodyA.damage(dmg); + if (whom[i].bodyB.alive) whom[i].bodyB.damage(dmg); + } + + + + //graphics + var gradient = ctx.createRadialGradient(this.position.x, this.position.y, 0, this.position.x, this.position.y, this.circleRadius); + gradient.addColorStop(0, `rgba(255,255,255,${this.alpha})`); + gradient.addColorStop(0.2, `rgba(255,200,255,${this.alpha})`); + gradient.addColorStop(1, `rgba(255,0,255,${this.alpha})`); + ctx.fillStyle = gradient + ctx.beginPath(); + ctx.arc(this.position.x, this.position.y, this.circleRadius, 0, 2 * Math.PI); + ctx.fill(); + } + }, + }); + Composite.add(engine.world, m.plasmaBall); + + m.hold = function() { + if (m.isHolding) { + m.drawHold(m.holdingTarget); + m.holding(); + m.throwBlock(); + } else if (input.field && m.fieldCDcycle < m.cycle) { //not hold but field button is pressed + m.grabPowerUp(); + m.lookForPickUp(); + + //field is active + if (!m.plasmaBall.isAttached) { //return ball to player + const scale = 0.7 + Matter.Body.scale(m.plasmaBall, scale, scale); //shrink fast + if (m.plasmaBall.circleRadius < m.plasmaBall.radiusLimit) { + m.plasmaBall.isAttached = true + m.plasmaBall.isOn = true + m.plasmaBall.setPositionToNose() + } + } else if (m.energy > m.plasmaBall.drain) { //charge up when attached + m.energy -= m.plasmaBall.drain; + const scale = 1 + 5 * Math.pow(Math.max(1, m.plasmaBall.circleRadius), -1.5) + Matter.Body.scale(m.plasmaBall, scale, scale); //grow + m.plasmaBall.setPositionToNose() + + //add friction for player when holding ball, maybe more friction in vertical + + + } else { + m.fieldCDcycle = m.cycle + 90; + m.plasmaBall.fire() + } + } else if (m.holdingTarget && m.fieldCDcycle < m.cycle) { //holding, but field button is released + m.pickUp(); + } else { + m.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 (m.plasmaBall.isAttached) { + m.fieldCDcycle = m.cycle + 30; + m.plasmaBall.fire() + } + } + m.drawFieldMeter("rgba(0, 0, 0, 0.2)") + + m.plasmaBall.do() + } + + + + } else if (tech.isExtruder) { m.hold = function() { b.isExtruderOn = false if (m.isHolding) { diff --git a/js/simulation.js b/js/simulation.js index 8fdcf1b..4e980d4 100644 --- a/js/simulation.js +++ b/js/simulation.js @@ -821,7 +821,7 @@ const simulation = { level.zones = []; simulation.drawList = []; - if (tech.isDronesTravel) { + if (tech.isDronesTravel && player.alive) { //count drones let count = 0 let deliveryCount = 0 @@ -945,7 +945,7 @@ const simulation = { } } - if (m.pos.y > simulation.fallHeight) { // if 4000px deep + if (m.pos.y > simulation.fallHeight || isNaN(player.position.x)) { // if 4000px deep Matter.Body.setVelocity(player, { x: 0, y: 0 diff --git a/js/spawn.js b/js/spawn.js index 84a05e9..5e4e4b6 100644 --- a/js/spawn.js +++ b/js/spawn.js @@ -3747,7 +3747,7 @@ const spawn = { if (this.countDown-- < 0) { //explode this.death(); //hit player - if (Vector.magnitude(Vector.sub(this.position, player.position)) < this.explodeRange) { + if (Vector.magnitude(Vector.sub(this.position, player.position)) < this.explodeRange && m.immuneCycle < m.cycle) { m.damage(0.01 * simulation.dmgScale * (tech.isRadioactiveResistance ? 0.25 : 1)); m.energy -= 0.1 * (tech.isRadioactiveResistance ? 0.25 : 1) if (m.energy < 0) m.energy = 0 diff --git a/js/tech.js b/js/tech.js index 37b91cf..7bd62cd 100644 --- a/js/tech.js +++ b/js/tech.js @@ -58,6 +58,7 @@ const tech = { simulation.makeTextLog(`tech.removeTech("${tech.tech[index].name}")`) tech.tech[index].remove(); tech.tech[index].count = 0; + tech.totalCount -= totalRemoved simulation.updateTechHUD(); tech.tech[index].isLost = true simulation.updateTechHUD(); @@ -211,7 +212,7 @@ const tech = { }, damageFromTech() { let dmg = 1 //m.fieldDamage - if (tech.isTechDebt) dmg *= 4 - 0.1 * tech.totalCount + if (tech.isTechDebt) dmg *= 4 - 0.08 * tech.totalCount if (tech.isAxion && tech.isHarmMACHO) dmg *= 1 + 0.75 * (1 - m.harmReduction()) if (tech.OccamDamage) dmg *= tech.OccamDamage if (tech.isCloakingDamage) dmg *= 1.35 @@ -370,7 +371,7 @@ const tech = { if (gunTechPool.length) { const index = Math.floor(Math.random() * gunTechPool.length) tech.giveTech(gunTechPool[index]) // choose from the gun pool - tech.tech[gunTechPool[index]].isFromAppliedScience = true //makes it not remove properly under pure science + tech.tech[gunTechPool[index]].isFromAppliedScience = true //makes it not remove properly under paradigm shift simulation.makeTextLog(`tech.giveTech("${tech.tech[gunTechPool[index]].name}")`) } } @@ -747,7 +748,7 @@ const tech = { }, { name: "regression", - description: "bullet collisions increase vulnerability to
damage by 6% for mobs (1% for bosses)", + description: "bullet collisions increase vulnerability to
damage by 5% for mobs (0.5% for bosses)", maxCount: 1, count: 0, frequency: 1, @@ -1620,7 +1621,7 @@ const tech = { }, { name: "Pauli exclusion", - description: `after receiving harm from a collision become
immune to harm for 1.5 extra seconds`, + description: `after receiving harm from a collision become
immune to harm for 2.5 extra seconds`, maxCount: 9, count: 0, frequency: 1, @@ -1628,7 +1629,7 @@ const tech = { allowed() { return true }, requires: "", effect() { - tech.collisionImmuneCycles += 90; + tech.collisionImmuneCycles += 150; if (m.immuneCycle < m.cycle + tech.collisionImmuneCycles) m.immuneCycle = m.cycle + tech.collisionImmuneCycles; //player is immune to damage }, remove() { @@ -1637,7 +1638,7 @@ const tech = { }, { name: "spin–statistics theorem", - description: `become immune to harm for 1.9 seconds
once every 7 seconds`, + description: `become immune to harm for 1.75 seconds
once every 7 seconds`, maxCount: 3, count: 0, frequency: 1, @@ -1647,7 +1648,7 @@ const tech = { }, requires: "", effect() { - tech.cyclicImmunity += 114; + tech.cyclicImmunity += 105; }, remove() { tech.cyclicImmunity = 0; @@ -3068,7 +3069,7 @@ const tech = { } }, { - name: "pure science", + name: "paradigm shift", description: `clicking tech while paused ejects them
4% chance to convert that tech into ${powerUps.orb.research(1)}`, maxCount: 1, count: 0, @@ -3088,7 +3089,7 @@ const tech = { // description: `increase damage by 300% minus 10% for tech you have learned(${4 - 0.1 * tech.totalCount})`, // description: `increase damage by 300%, but reduce damage
by 10% for tech you have learned`, descriptionFunction() { - return `increase damage by 300% minus 10%
for tech you have learned (${Math.floor(100*(4 - 0.1 * tech.totalCount))-100}%)` + return `increase damage by 300% minus 8%
for tech you have learned (${Math.floor(100*(4 - 0.08 * tech.totalCount))-100}%)` }, maxCount: 1, count: 0, @@ -3704,7 +3705,7 @@ const tech = { frequency: 2, frequencyDefault: 2, allowed() { - return ((tech.haveGunCheck("nail gun") && !tech.nailInstantFireRate && !tech.nailRecoil) || (tech.haveGunCheck("shotgun") && !tech.isNailShot && !tech.isFoamShot && !tech.isSporeWorm)) && !tech.isRivets && !tech.isIncendiary && !tech.isIceCrystals + return ((tech.haveGunCheck("nail gun") && !tech.nailInstantFireRate && !tech.nailRecoil) || (tech.haveGunCheck("shotgun") && !tech.isNailShot && !tech.isFoamShot && !tech.isSporeWorm)) && !tech.isRivets && !tech.isIncendiary && !tech.isIceCrystals && !tech.isIceShot }, requires: "nail gun, shotgun, not ice crystal, rivets, rotary cannon, or pneumatic, incendiary, nail-shot, rivets, foam-shot, worm-shot, ice-shot", effect() { @@ -3743,7 +3744,7 @@ const tech = { frequency: 2, frequencyDefault: 2, allowed() { - return ((tech.haveGunCheck("nail gun") && !tech.nailInstantFireRate) || (tech.haveGunCheck("shotgun") && !tech.isNailShot && !tech.isFoamShot && !tech.isSporeWorm)) && !tech.isNeedles && !tech.isIceCrystals + return ((tech.haveGunCheck("nail gun") && !tech.nailInstantFireRate) || (tech.haveGunCheck("shotgun") && !tech.isNailShot && !tech.isFoamShot && !tech.isSporeWorm)) && !tech.isNeedles && !tech.isIceCrystals && !tech.isIceShot }, requires: "nail gun shot gun, not ice crystal, needles, or pneumatic actuator", effect() { @@ -5004,7 +5005,7 @@ const tech = { name: "annelids", description: "increase worm size and damage
between 10% and 120%", isGunTech: true, - maxCount: 9, + maxCount: 3, count: 0, frequency: 3, frequencyDefault: 3, @@ -6445,7 +6446,7 @@ const tech = { frequency: 3, frequencyDefault: 3, allowed() { - return (build.isExperimentSelection || powerUps.research.count > 0) && m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && !(tech.isMissileField || tech.isIceField || tech.isFastDrones || tech.isDroneGrab || tech.isDroneRadioactive || tech.isDroneTeleport) + return (build.isExperimentSelection || powerUps.research.count > 0) && m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && !(tech.isMissileField || tech.isIceField || tech.isFastDrones || tech.isDroneGrab || tech.isDroneRadioactive || tech.isDroneTeleport || tech.isDronesTravel) }, requires: "molecular assembler, no other manufacturing, no drone tech", effect() { @@ -6472,7 +6473,7 @@ const tech = { frequency: 3, frequencyDefault: 3, allowed() { - return (build.isExperimentSelection || powerUps.research.count > 0) && m.maxEnergy > 0.5 && m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && !(tech.isSporeField || tech.isIceField || tech.isFastDrones || tech.isDroneGrab || tech.isDroneRadioactive || tech.isDroneTeleport) + return (build.isExperimentSelection || powerUps.research.count > 0) && m.maxEnergy > 0.5 && m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && !(tech.isSporeField || tech.isIceField || tech.isFastDrones || tech.isDroneGrab || tech.isDroneRadioactive || tech.isDroneTeleport || tech.isDronesTravel) }, requires: "molecular assembler, no other manufacturing, no drone tech", effect() { @@ -6499,7 +6500,7 @@ const tech = { frequency: 3, frequencyDefault: 3, allowed() { - return (build.isExperimentSelection || powerUps.research.count > 0) && m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && !(tech.isSporeField || tech.isMissileField || tech.isFastDrones || tech.isDroneGrab || tech.isDroneRadioactive || tech.isDroneTeleport) + return (build.isExperimentSelection || powerUps.research.count > 0) && m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && !(tech.isSporeField || tech.isMissileField || tech.isFastDrones || tech.isDroneGrab || tech.isDroneRadioactive || tech.isDroneTeleport || tech.isDronesTravel) }, requires: "molecular assembler, no other manufacturing, no drone tech", effect() { @@ -6635,6 +6636,27 @@ const tech = { if (this.count > 0) powerUps.research.changeRerolls(this.count * 2) } }, + { + name: "plasma ball", + description: "charge up a ball of plasma and fire it", + isFieldTech: true, + maxCount: 1, + count: 0, + frequency: 2, + frequencyDefault: 2, + allowed() { + return m.fieldUpgrades[m.fieldMode].name === "plasma torch" && !tech.isExtruder + }, + requires: "plasma torch, not extruder", + effect() { + tech.isPlasmaBall = true; + m.fieldUpgrades[m.fieldMode].set() + }, + remove() { + tech.isPlasmaBall = false; + if (this.count) m.fieldUpgrades[m.fieldMode].set() + } + }, { name: "extruder", description: "plasma torch extrudes a thin hot wire
increases damage and energy drain", @@ -6644,9 +6666,9 @@ const tech = { frequency: 2, frequencyDefault: 2, allowed() { - return m.fieldUpgrades[m.fieldMode].name === "plasma torch" + return m.fieldUpgrades[m.fieldMode].name === "plasma torch" && !tech.isPlasmaBall }, - requires: "plasma torch", + requires: "plasma torch, not plasma ball", effect() { tech.isExtruder = true; m.fieldUpgrades[m.fieldMode].set() @@ -7642,54 +7664,6 @@ const tech = { if (this.count) m.look = m.lookDefault } }, - { - name: "Mech v4.48", - description: `open a portal to a primordial version of reality`, - maxCount: 1, - count: 0, - frequency: 0, - isNonRefundable: true, - isJunk: true, - allowed() { return true }, - requires: "", - effect() { - window.open('https://scratch.mit.edu/projects/14005697/fullscreen/', '_blank') - }, - remove() {} - }, - { - name: "planetesimals", - description: `play planetesimals (an asteroids-like game)
clear levels in planetesimals to spawn tech
if you die in planetesimals you die in n-gon`, - maxCount: 1, - count: 0, - frequency: 0, - isNonRefundable: true, - isJunk: true, - allowed() { return true }, - requires: "", - effect() { - window.open('../../planetesimals/index.html', '_blank') - // powerUps.spawn(m.pos.x, m.pos.y, "tech"); - - // for communicating to other tabs, like planetesimals - // Connection to a broadcast channel - const bc = new BroadcastChannel('planetesimals'); - bc.activated = false - - bc.onmessage = function(ev) { - if (ev.data === 'tech') powerUps.directSpawn(m.pos.x, m.pos.y, "tech"); - if (ev.data === 'death') { - m.death() - bc.close(); //end session - } - if (ev.data === 'ready' && !bc.activated) { - bc.activated = true //prevents n-gon from activating multiple copies of planetesimals - bc.postMessage("activate"); - } - } - }, - remove() {} - }, { name: "facsimile", description: `inserts a copy of your current level into the level list`, @@ -9165,6 +9139,54 @@ const tech = { }, remove() {} }, + { + name: "Mech v4.48", + description: `open a portal to a primordial version of reality`, + maxCount: 1, + count: 0, + frequency: 0, + isNonRefundable: true, + isJunk: true, + allowed() { return true }, + requires: "", + effect() { + window.open('https://scratch.mit.edu/projects/14005697/fullscreen/', '_blank') + }, + remove() {} + }, + { + name: "planetesimals", + description: `play planetesimals (an asteroids-like game)
clear levels in planetesimals to spawn tech
if you die in planetesimals you die in n-gon`, + maxCount: 1, + count: 0, + frequency: 0, + isNonRefundable: true, + isJunk: true, + allowed() { return true }, + requires: "", + effect() { + window.open('../../planetesimals/index.html', '_blank') + // powerUps.spawn(m.pos.x, m.pos.y, "tech"); + + // for communicating to other tabs, like planetesimals + // Connection to a broadcast channel + const bc = new BroadcastChannel('planetesimals'); + bc.activated = false + + bc.onmessage = function(ev) { + if (ev.data === 'tech') powerUps.directSpawn(m.pos.x, m.pos.y, "tech"); + if (ev.data === 'death') { + m.death() + bc.close(); //end session + } + if (ev.data === 'ready' && !bc.activated) { + bc.activated = true //prevents n-gon from activating multiple copies of planetesimals + bc.postMessage("activate"); + } + } + }, + remove() {} + }, //************************************************** //************************************************** undefined / lore //************************************************** tech @@ -9537,5 +9559,6 @@ const tech = { isGrapple: null, isImmuneGrapple: null, isDronesTravel: null, - isTechDebt: null + isTechDebt: null, + isPlasmaBall: null } \ No newline at end of file diff --git a/style.css b/style.css index 9d68c28..1c64d15 100644 --- a/style.css +++ b/style.css @@ -236,7 +236,7 @@ summary { margin: 0px; display: none; - grid-template-columns: 320px; + grid-template-columns: 325px; /* grid-template-columns: repeat(auto-fit, minmax(310px, 1fr)); */ grid-auto-rows: minmax(auto, auto); grid-gap: 0px; diff --git a/todo.txt b/todo.txt index 555b5cc..71b40e8 100644 --- a/todo.txt +++ b/todo.txt @@ -1,20 +1,62 @@ ******************************************************** NEXT PATCH ************************************************** -tech: autonomous navigation - drones travel with you through levels and drones reset durability -tech: technical debt - increase damage by 300%, but reduce damage by 10% for each tech you have +plasma ball is now live, but it's still in beta + still needs + new graphics + damage balancing + fast decay in mob shields + player angle rotation speed while firing adds to fire speed + tech upgrade to get electrical arcs that randomly damage nearby mobs + current tech synergy + capacitor bank,plasma jet(range?) -molecular assembler now has a higher bullet spawn cap 200->300 - but it increases energy cost per spawn above around 150 +reservoir level is less crowded, so you can dodge mobs easier + horizontal flipped version is so reenabled +pure science renamed paradigm shift +difficulty scaling for heal and mob damage reduced 2% -fragments are about 15% fewer -thermal runaway is about 40% bigger and more damage -plasma torch: extruder uses less energy -pilot wave uses less energy +some possible bug fixes, I don't know... -bug fixes ******************************************************** TODO ******************************************************** +bug: harpoon attack gave a mob really high levels of health + recent events: + had 3 harpoons at a time + tech: immune with grappling hook, Bulk modulus + cancel true colors with pure science + attack with harpoon at slasher mobs + they didn't die, but they should in one hit instead they got a huge health bar, then I just died for no reason after touching one + +bug: maybe I can put in an event listener to reset inputs to false when you tab out to prevent key sticking + + +enemies stuck with foam receive upward force over time + only form aerogel tech? + +bug: often game puts player position at NaN + try: + cloaking/harpoon grapple on normal, continue past beating the final boss + clues: + maybe with vanish or other special blocks and grapple hook + very high level for tech, duplication + maybe not about JUNK though + maybe on tons of bullets + maybe grappling hook, Bulk modulus + solution: just kill the player if they go NaN + +Tech: superglue +Requires: foam + another gun or plasma torch or molecular assembler + Foam bubbles decay 50% slower + Enemies stuck with foam cannot move + Foam does 0 damage + Enemies stuck with foam take 25% more damage + should foam bots gets this also or is that too strong + + +buff pilot wave damage or lower energy drain +lower base harpoon density + const ctx = canvas.getContext('2d', {‘willReadFrequently': true}); //deal with game crashes? @@ -33,22 +75,10 @@ setting to remove UI, except health bar except active gun? to see ammo checkbox in pause and in settings -bug: often game puts player position at NaN - clues: - after apoximis? - very high level for tech, duplication - maybe not about JUNK though - -tech that does less damage the more tech you have? - tech.totalCount - add coyote jump log game m.cycle when last on ground for jump check if game cycle is < last on ground cycle -2 -tech - Plasma railgun - like foam, or phonon? - pause time like invariant for other things... throwing blocks charging railgun