diff --git a/.DS_Store b/.DS_Store index 4469fa6..a18c0cc 100644 Binary files a/.DS_Store and b/.DS_Store differ 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