diff --git a/.DS_Store b/.DS_Store index 2229428..697f9d7 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/js/bullet.js b/js/bullet.js index e3af1fc..750bbaf 100644 --- a/js/bullet.js +++ b/js/bullet.js @@ -3122,10 +3122,9 @@ const b = { this.target.damage(m.dmgScale * this.damage); } } else if (this.target !== null) { //look for a new target - this.target = null this.collisionFilter.category = cat.bullet; this.collisionFilter.mask = cat.mob //| cat.mobShield //cat.map | cat.body | cat.mob | cat.mobBullet | cat.mobShield - if (tech.isFoamGrowOnDeath && bullet.length < 180) { + if (tech.isFoamGrowOnDeath && 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)); @@ -3147,6 +3146,7 @@ const b = { } } } + 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, { @@ -5581,7 +5581,7 @@ const b = { name: "harpoon", description: "fire a self-steering harpoon that uses energy
to retract and refund its ammo cost", ammo: 0, - ammoPack: 1, + ammoPack: 0.3, have: false, do() {}, fire() { diff --git a/js/engine.js b/js/engine.js index 2de2465..7a5490c 100644 --- a/js/engine.js +++ b/js/engine.js @@ -135,7 +135,7 @@ function collisionChecks(event) { } if (tech.isPiezo) m.energy += 20.48; if (tech.isStimulatedEmission) powerUps.ejectTech() - if (mob[k].onHit) mob[k].onHit(k); + if (mob[k].onHit) mob[k].onHit(); if (m.immuneCycle < m.cycle + tech.collisionImmuneCycles) m.immuneCycle = m.cycle + tech.collisionImmuneCycles; //player is immune to damage for 30 cycles //extra kick between player and mob //this section would be better with forces but they don't work... let angle = Math.atan2(player.position.y - mob[k].position.y, player.position.x - mob[k].position.x); diff --git a/js/level.js b/js/level.js index 3ee2458..adeff64 100644 --- a/js/level.js +++ b/js/level.js @@ -15,7 +15,7 @@ const level = { start() { if (level.levelsCleared === 0) { //this code only runs on the first level // simulation.isHorizontalFlipped = true - // m.setField("standing wave") + // m.setField("time dilation") // b.giveGuns("harpoon") // for (let i = 0; i < 100; i++) tech.giveTech("slow light") // tech.giveTech("tungsten carbide") @@ -30,7 +30,7 @@ const level = { // tech.tech[297].frequency = 100 // m.immuneCycle = Infinity //you can't take damage - // level.difficultyIncrease(30) //30 is near max on hard //60 is near max on why + // level.difficultyIncrease(15) //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 @@ -2617,13 +2617,13 @@ const level = { spawn.mapRect(-400, -750, 625, 1200); // spawn.mapVertex(200, 0, "-200 0 -100 -100 100 -100 200 0"); - spawn.bodyRect(225, -100, 100, 100, 0.5); - spawn.bodyRect(225, -200, 75, 100, 0.5); - spawn.bodyRect(325, -70, 150, 70, 1); - spawn.bodyRect(-275, -850, 75, 100, 0.4); - spawn.bodyRect(1525, -100, 100, 100, 0.3); - spawn.bodyRect(2325, -50, 125, 50, 0.3); - spawn.bodyRect(2375, -100, 50, 50, 0.3); + // spawn.bodyRect(225, -100, 100, 100, 0.5); + // spawn.bodyRect(225, -200, 75, 100, 0.5); + spawn.bodyRect(250, -70, 100, 70, 1); + // spawn.bodyRect(-275, -850, 75, 100, 0.4); + // spawn.bodyRect(1525, -100, 100, 100, 0.3); + // spawn.bodyRect(2325, -50, 125, 50, 0.3); + // spawn.bodyRect(2375, -100, 50, 50, 0.3); for (let i = 0; i < 3; ++i) powerUps.spawn(400 + 2000 * Math.random(), -25, "ammo"); spawn.mapRect(-425, 0, 4200, 2100); @@ -2700,10 +2700,12 @@ const level = { doorOut.isClosing = true if (!isSpawnedBoss) { isSpawnedBoss = true - if (Math.random() > 0.5) { + if (Math.random() < 0.33) { for (let i = 0, len = Math.min(simulation.difficulty / 20, 5); i < len; ++i) spawn.bounceBoss(1487 + 200 * i, -1525, 80, false); - } else { + } else if (Math.random() < 0.5) { for (let i = 0, len = Math.min(simulation.difficulty / 10, 10); i < len; ++i) spawn.sprayBoss(2400 - 150 * i, -225, 30, false) + } else { + for (let i = 0, len = Math.min(simulation.difficulty / 8, 10); i < len; ++i) spawn.mineBoss(1950, -250, 50, false); } // for (let i = 0, len = 3 + simulation.difficulty / 20; i < len; ++i) spawn.mantisBoss(1487 + 300 * i, -1525, 35, false) } diff --git a/js/player.js b/js/player.js index ce1975f..df503f0 100644 --- a/js/player.js +++ b/js/player.js @@ -514,7 +514,7 @@ const m = { if (tech.isSlowFPS) dmg *= 0.8 if (tech.isHarmReduce && input.field && m.fieldCDcycle < m.cycle) dmg *= 0.4 if (tech.isNeutronium && input.field && m.fieldCDcycle < m.cycle) dmg *= 0.1 - if (tech.isBotArmor) dmg *= 0.92 ** b.totalBots() + if (tech.isBotArmor) dmg *= 0.93 ** b.totalBots() if (tech.isHarmArmor && m.lastHarmCycle + 600 > m.cycle) dmg *= 0.33; if (tech.isNoFireDefense && m.cycle > m.fireCDcycle + 120) dmg *= 0.3 if (tech.energyRegen === 0) dmg *= 0.34 @@ -3618,7 +3618,7 @@ const m = { m.damage(dmg); if (tech.isPiezo) m.energy += 20.48; if (tech.isStimulatedEmission) powerUps.ejectTech() - if (mob[k].onHit) mob[k].onHit(k); + if (mob[k].onHit) mob[k].onHit(); if (m.immuneCycle < m.cycle + tech.collisionImmuneCycles) m.immuneCycle = m.cycle + tech.collisionImmuneCycles; //player is immune to damage for 30 cycles //extra kick between player and mob //this section would be better with forces but they don't work... let angle = Math.atan2(player.position.y - mob[k].position.y, player.position.x - mob[k].position.x); diff --git a/js/powerup.js b/js/powerup.js index beb02df..c4679eb 100644 --- a/js/powerup.js +++ b/js/powerup.js @@ -306,11 +306,6 @@ const powerUps = { const index = powerUps.tech.choiceLog.length - i - 1 if (powerUps.tech.choiceLog[index] && tech.tech[powerUps.tech.choiceLog[index]]) { tech.tech[powerUps.tech.choiceLog[index]].isBanished = true - } else { //if no tech options available eject banish tech - for (let i = 0, len = tech.tech.length; i < len; i++) { - if (tech.tech[i].name === "decoherence") powerUps.ejectTech(i) - } - powerUps.endDraft("tech"); } } simulation.makeTextLog(`powerUps.tech.length: ${Math.max(0,powerUps.tech.lastTotalChoices - banishLength)}`) @@ -404,18 +399,7 @@ const powerUps = { const banishLength = tech.isDeterminism ? 1 : 3 + tech.isExtraChoice * 2 for (let i = 0; i < banishLength; i++) { const index = powerUps.tech.choiceLog.length - i - 1 - // console.log(index) - // console.log(powerUps.tech.choiceLog.length) - // console.log(powerUps.tech.choiceLog[index]) - // console.log(tech.tech[powerUps.tech.choiceLog[index]]) - if (powerUps.tech.choiceLog[index] && tech.tech[powerUps.tech.choiceLog[index]]) { - tech.tech[powerUps.tech.choiceLog[index]].isBanished = true - } else { //if no tech options available eject banish tech - for (let i = 0, len = tech.tech.length; i < len; i++) { - if (tech.tech[i].name === "decoherence") powerUps.ejectTech(i) - } - powerUps.endDraft("tech"); - } + if (powerUps.tech.choiceLog[index] && tech.tech[powerUps.tech.choiceLog[index]]) tech.tech[powerUps.tech.choiceLog[index]].isBanished = true } simulation.makeTextLog(`powerUps.tech.length: ${Math.max(0,powerUps.tech.lastTotalChoices - banishLength)}`) } @@ -697,6 +681,10 @@ const powerUps = { // text += `
  ${tech.tech[choose].name}
${tech.tech[choose].description}
` return choose + } else if (tech.isBanish) { //if no tech options available eject banish tech + for (let i = 0, len = tech.tech.length; i < len; i++) { + if (tech.tech[i].name === "decoherence") powerUps.ejectTech(i) + } } } @@ -704,7 +692,7 @@ const powerUps = { if (!tech.isSuperDeterminism) text += `
` text += `

tech

` let choice1 = pick() - console.log(choice1) + // console.log(choice1) let choice2 = null let choice3 = null if (choice1 !== null) { diff --git a/js/spawn.js b/js/spawn.js index 704d314..7c1e786 100644 --- a/js/spawn.js +++ b/js/spawn.js @@ -3617,6 +3617,160 @@ const spawn = { me.do = me.noFire Matter.Body.setVelocity(me, { x: 10 * (Math.random() - 0.5), y: 10 * (Math.random() - 0.5) }); }, + mineBoss(x, y, radius = 120, isSpawnBossPowerUp = true) { + mobs.spawn(x, y, 0, radius, "rgba(255,255,255,0.5)") // "rgb(201,202,225)"); + let me = mob[mob.length - 1]; + // Matter.Body.rotate(me, 2 * Math.PI * Math.random()); + me.isBoss = true; + Matter.Body.setDensity(me, 0.001); //normal is 0.001 + me.inertia = Infinity; + me.damageReduction = 0.04 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) + me.startingDamageReduction = me.damageReduction + me.isInvulnerable = false + me.frictionAir = 0.01 + me.restitution = 1 + me.friction = 0 + me.collisionFilter.mask = cat.bullet | cat.player | cat.body | cat.map | cat.mob + me.explodeRange = 400 + Matter.Body.setVelocity(me, { x: 10 * (Math.random() - 0.5), y: 10 * (Math.random() - 0.5) }); + me.seePlayer.recall = 1; + // spawn.shield(me, x, y, 1); + me.onDamage = function() { + if (this.health < this.nextHealthThreshold) { + this.health = this.nextHealthThreshold - 0.01 + this.nextHealthThreshold = Math.floor(this.health * 4) / 4 + this.invulnerableCount = 60 + simulation.difficulty * 1.5 + this.isInvulnerable = true + this.damageReduction = 0 + + //slow time to look cool + // simulation.fpsCap = 10 //new fps + // simulation.fpsInterval = 1000 / simulation.fpsCap; + //how long to wait to return to normal fps + // m.defaultFPSCycle = m.cycle + 20 + 90 + + + for (let i = 0, len = mob.length; i < len; ++i) { //trigger nearby mines + if (mob[i].isMine && Vector.magnitude(Vector.sub(this.position, mob[i].position)) < this.explodeRange) mob[i].isExploding = true + } + simulation.drawList.push({ //add dmg to draw queue + x: this.position.x, + y: this.position.y, + radius: this.explodeRange, + color: "rgba(255,25,0,0.6)", + time: simulation.drawTime * 2 + }); + + } + }; + me.onDeath = function() { + if (isSpawnBossPowerUp) powerUps.spawnBossPowerUp(this.position.x, this.position.y) + for (let i = 0, len = mob.length; i < len; ++i) { //trigger nearby mines + if (mob[i].isMine && Vector.magnitude(Vector.sub(this.position, mob[i].position)) < this.explodeRange) mob[i].isExploding = true + } + }; + me.cycle = 0 + me.nextHealthThreshold = 0.75 + me.invulnerableCount = 0 + // console.log(me.mass) //100 + me.do = function() { + me.seePlayer.recall = 1 + //maintain speed //faster in the vertical to help avoid repeating patterns + if (this.speed < 0.01) { + const unit = Vector.sub(player.position, this.position) + Matter.Body.setVelocity(this, Vector.mult(Vector.normalise(unit), 0.1)); + // this.invulnerableCount = 10 + simulation.difficulty * 0.5 + // this.isInvulnerable = true + // this.damageReduction = 0 + } else { + if (Math.abs(this.velocity.y) < 10) { + Matter.Body.setVelocity(this, { x: this.velocity.x, y: this.velocity.y * 1.03 }); + } + if (Math.abs(this.velocity.x) < 7) { + Matter.Body.setVelocity(this, { x: this.velocity.x * 1.03, y: this.velocity.y }); + } + } + if (this.isInvulnerable) { + this.invulnerableCount-- + if (this.invulnerableCount < 0) { + this.isInvulnerable = false + this.damageReduction = this.startingDamageReduction + } + //draw invulnerable + ctx.beginPath(); + let vertices = this.vertices; + ctx.moveTo(vertices[0].x, vertices[0].y); + for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y); + ctx.lineTo(vertices[0].x, vertices[0].y); + ctx.lineWidth = 20; + ctx.strokeStyle = "rgba(255,255,255,0.7)"; + ctx.stroke(); + } + this.checkStatus(); + if (!(simulation.cycle % 15) && mob.length < 360) spawn.mine(this.position.x, this.position.y) + }; + }, + mine(x, y) { + mobs.spawn(x, y, 8, 10, "rgb(100,170,150)"); + let me = mob[mob.length - 1]; + me.stroke = "transparent"; + Matter.Body.setDensity(me, 0.0001); //normal is 0.001 + // Matter.Body.setStatic(me, true); //make static (disables taking damage) + me.frictionAir = 1 + me.damageReduction = 2 + me.collisionFilter.category = cat.mobBullet; + me.collisionFilter.mask = cat.bullet | cat.body // | cat.player + me.isMine = true + me.leaveBody = false; + me.isDropPowerUp = false; + me.isBadTarget = true; + me.isMobBullet = true; + me.showHealthBar = false; + me.explodeRange = 200 + 150 * Math.random() + me.isExploding = false + me.countDown = Math.ceil(4 * Math.random()) + + // me.onHit = function() { + // this.isExploding = true + // }; + // me.onDamage = function() { + // this.health = 1 + // this.isExploding = true + // }; + me.do = function() { + this.checkStatus(); + + if (Matter.Query.collides(this, [player]).length > 0) { + this.isExploding = true + } + + if (this.isExploding) { + if (this.countDown-- < 0) { //explode + this.death(); + //hit player + if (Vector.magnitude(Vector.sub(this.position, player.position)) < this.explodeRange) { + m.damage(0.008 * simulation.dmgScale); + const DRAIN = 0.08 * (tech.isRadioactiveResistance ? 0.25 : 1) + if (m.energy > DRAIN) m.energy -= DRAIN + } + // mob[i].isInvulnerable = false //make mineBoss not invulnerable ? + const range = this.explodeRange + 50 //mines get a slightly larger range to explode + for (let i = 0, len = mob.length; i < len; ++i) { + if (mob[i].alive && Vector.magnitude(Vector.sub(this.position, mob[i].position)) < range) { + if (mob[i].isMine) mob[i].isExploding = true //explode other mines + } + } + simulation.drawList.push({ //add dmg to draw queue + x: this.position.x, + y: this.position.y, + radius: this.explodeRange, + color: "rgba(80,220,190,0.45)", + time: 16 + }); + } + } + }; + }, bounceBoss(x, y, radius = 80, isSpawnBossPowerUp = true) { mobs.spawn(x, y, 0, radius, "rgb(255,255,255)") // "rgb(201,202,225)"); let me = mob[mob.length - 1]; @@ -3659,10 +3813,10 @@ const spawn = { // this.damageReduction = 0 } else { if (Math.abs(this.velocity.y) < 15) { - Matter.Body.setVelocity(this, { x: this.velocity.x, y: this.velocity.y * 1.07 }); + Matter.Body.setVelocity(this, { x: this.velocity.x, y: this.velocity.y * 1.03 }); } if (Math.abs(this.velocity.x) < 11) { - Matter.Body.setVelocity(this, { x: this.velocity.x * 1.07, y: this.velocity.y }); + Matter.Body.setVelocity(this, { x: this.velocity.x * 1.03, y: this.velocity.y }); } } diff --git a/js/tech.js b/js/tech.js index 868c63f..91ad327 100644 --- a/js/tech.js +++ b/js/tech.js @@ -234,7 +234,7 @@ const tech = { if (tech.isOneGun && b.inventory.length < 2) dmg *= 1.25 if (tech.isNoFireDamage && m.cycle > m.fireCDcycle + 120) dmg *= 2 if (tech.isSpeedDamage) dmg *= 1 + Math.min(0.66, player.speed * 0.0165) - if (tech.isBotDamage) dmg *= 1 + 0.07 * b.totalBots() + if (tech.isBotDamage) dmg *= 1 + 0.06 * b.totalBots() if (tech.isDamageAfterKillNoRegen && m.lastKillCycle + 300 > m.cycle) dmg *= 1.5 return dmg * tech.slowFire * tech.aimDamage }, @@ -1395,7 +1395,7 @@ const tech = { }, { name: "perimeter defense", - description: "reduce harm by 8%
for each of your permanent bots", + description: "reduce harm by 7%
for each of your permanent bots", maxCount: 1, count: 0, frequency: 2, @@ -1414,7 +1414,7 @@ const tech = { }, { name: "network effect", - description: "increase damage by 7%
for each of your permanent bots", + description: "increase damage by 6%
for each of your permanent bots", maxCount: 1, count: 0, frequency: 2, @@ -7768,7 +7768,7 @@ const tech = { }, { name: "emergency broadcasting", - description: "emit 2 sound sine waveforms at 853 Hz and 960 Hz
lower your volume", + description: "emit 2 sine waveforms at 853 Hz and 960 Hz
lower your volume", maxCount: 1, count: 0, frequency: 0, diff --git a/todo.txt b/todo.txt index 453bdd2..530b9fe 100644 --- a/todo.txt +++ b/todo.txt @@ -1,17 +1,33 @@ ******************************************************** NEXT PATCH ************************************************** -new sprayBoss on reactor level - shows up 50% of the time - unbalanced right now, so give me feedback +new reactor boss - mineBoss + 1/3 chance for 1 of 3 different bosses to spawn on the reactor level + +harpoon starts with 10->3 ammo, and still gets 1 ammo per powerUpx +network effect damage per bot 7->6% +perimeter defense harm reduction 8->7% + +bug fix decoherence ******************************************************** TODO ******************************************************** ++damage for each different bot type you have + disables bot upgrades? + +improve rail gun / use ammo to crouch fire style for harpoon + spend ammo to get some tech + ammo cost on reticulum + spend ammo to make harpoon radioactive + tech disables filament and unaaq? probably don't need to + give rail gun the auto targeting + improve auto-target with a tech? + you already tried this and target probably can't get better + try to get grappling hook working again + tech doing damage refunds up to 50% of damage take in last 10 seconds - use history to manage this? + use history[] to manage this? -tech: frozen mobs dies at 10% life - -CPt disables the falling damage tech +tech: frozen mobs die at 10% life make a seed/hash system that controls only the tech/guns/fields shown URL sharing could include a seed @@ -24,7 +40,6 @@ make a seed/hash system that controls only the tech/guns/fields shown give 1 extra tech for doing the daily seeded run make the option for the daily run, a secret exit in the intro level? - tech upgrade to anthropic principle to make it trigger at 50% life and 0% once per map JUNK tech: https://bindingofisaacrebirth.fandom.com/wiki/Damocles @@ -33,10 +48,10 @@ cloaking field doesn't show energy over max run more profiles of n-gon to fix performance issues -sprayBoss - reactor or everywhere? - reactor + mineBoss - bounces around and drops mines + mines explode with a large radius that can trigger other mines + mines have a short delay before exploding so they don't all go up in the same cycle life-like cellular automata boss https://scratch.mit.edu/projects/77724260/ night/day?