diff --git a/js/bullet.js b/js/bullet.js index 7dea5e7..8d1d258 100644 --- a/js/bullet.js +++ b/js/bullet.js @@ -1207,18 +1207,18 @@ const b = { m.energy = 0; } b.isExtruderOn = true - const SPEED = 8 + const SPEED = 14 const me = bullet.length; const where = Vector.add(m.pos, player.velocity) bullet[me] = Bodies.polygon(where.x + 20 * Math.cos(m.angle), where.y + 20 * Math.sin(m.angle), 4, 0.01, { cycle: -0.5, isWave: true, - endCycle: simulation.cycle + 35 + 45 * tech.isPlasmaRange, + endCycle: simulation.cycle + 53, // + 30 * tech.isPlasmaRange, inertia: Infinity, frictionAir: 0, isInHole: true, //this keeps the bullet from entering wormholes minDmgSpeed: 0, - dmg: b.dmgScale * 1.2, //damage also changes when you divide by mob.mass on in .do() + dmg: b.dmgScale * 1.5, //damage also changes when you divide by mob.mass on in .do() classType: "bullet", isBranch: false, restitution: 0, @@ -1270,7 +1270,7 @@ const b = { y: SPEED * Math.sin(m.angle) }); const transverse = Vector.normalise(Vector.perp(bullet[me].velocity)) - if (180 - Math.abs(Math.abs(b.lastAngle - m.angle) - 180) > 0.3) bullet[me].isBranch = true; //don't draw stroke for this bullet + if (180 - Math.abs(Math.abs(b.lastAngle - m.angle) - 180) > 0.13) bullet[me].isBranch = true; //don't draw stroke for this bullet b.lastAngle = m.angle //track last angle for the above angle difference calculation if (!b.wasExtruderOn) bullet[me].isBranch = true; } else { @@ -1825,119 +1825,122 @@ const b = { }, spore(where, isFreeze = tech.isSporeFreeze) { //used with the tech upgrade in mob.death() const bIndex = bullet.length; - const side = 4; - bullet[bIndex] = Bodies.polygon(where.x, where.y, 4, side, { - // density: 0.0015, //frictionAir: 0.01, - inertia: Infinity, - isFreeze: isFreeze, - restitution: 0.5, - angle: Math.random() * 2 * Math.PI, - friction: 0, - frictionAir: 0.025, - thrust: (tech.isFastSpores ? 0.001 : 0.0004) * (1 + 0.3 * (Math.random() - 0.5)), - dmg: tech.isMutualism ? 12 : 5, //bonus damage from tech.isMutualism - lookFrequency: 100 + Math.floor(117 * Math.random()), - classType: "bullet", - collisionFilter: { - category: cat.bullet, - mask: cat.map | cat.mob | cat.mobBullet | cat.mobShield //no collide with body - }, - endCycle: simulation.cycle + Math.floor((600 + Math.floor(Math.random() * 420)) * tech.isBulletsLastLonger), - minDmgSpeed: 0, - playerOffPosition: { //used when moving towards player to keep spores separate - x: 100 * (Math.random() - 0.5), - y: 100 * (Math.random() - 0.5) - }, - beforeDmg(who) { - this.endCycle = 0; //bullet ends cycle after doing damage - if (this.isFreeze) mobs.statusSlow(who, 90) - }, - onEnd() { - if (tech.isMutualism && this.isMutualismActive && !tech.isEnergyHealth) { - m.health += 0.005 - if (m.health > m.maxHealth) m.health = m.maxHealth; - m.displayHealth(); - } - }, - do() { - if (this.lockedOn && this.lockedOn.alive) { - this.force = Vector.mult(Vector.normalise(Vector.sub(this.lockedOn.position, this.position)), this.mass * this.thrust) - } else { - if (!(simulation.cycle % this.lookFrequency)) { //find mob targets - this.closestTarget = null; - this.lockedOn = null; - let closeDist = Infinity; - for (let i = 0, len = mob.length; i < len; ++i) { - if (mob[i].dropPowerUp && Matter.Query.ray(map, this.position, mob[i].position).length === 0) { - const targetVector = Vector.sub(this.position, mob[i].position) - const dist = Vector.magnitude(targetVector) * (Math.random() + 0.5); - if (dist < closeDist) { - this.closestTarget = mob[i].position; - closeDist = dist; - this.lockedOn = mob[i] - if (0.3 > Math.random()) break //doesn't always target the closest mob + if (bIndex < 500) { //can't make over 500 spores + bullet[bIndex] = Bodies.polygon(where.x, where.y, 4, 4, { + // density: 0.0015, //frictionAir: 0.01, + inertia: Infinity, + isFreeze: isFreeze, + restitution: 0.5, + angle: Math.random() * 2 * Math.PI, + friction: 0, + frictionAir: 0.025, + thrust: (tech.isFastSpores ? 0.001 : 0.0004) * (1 + 0.3 * (Math.random() - 0.5)), + dmg: tech.isMutualism ? 12 : 5, //bonus damage from tech.isMutualism + lookFrequency: 100 + Math.floor(117 * Math.random()), + classType: "bullet", + collisionFilter: { + category: cat.bullet, + mask: cat.map | cat.mob | cat.mobBullet | cat.mobShield //no collide with body + }, + endCycle: simulation.cycle + Math.floor((600 + Math.floor(Math.random() * 420)) * tech.isBulletsLastLonger), + minDmgSpeed: 0, + playerOffPosition: { //used when moving towards player to keep spores separate + x: 100 * (Math.random() - 0.5), + y: 100 * (Math.random() - 0.5) + }, + beforeDmg(who) { + this.endCycle = 0; //bullet ends cycle after doing damage + if (this.isFreeze) mobs.statusSlow(who, 90) + }, + onEnd() { + if (tech.isMutualism && this.isMutualismActive && !tech.isEnergyHealth) { + m.health += 0.005 + if (m.health > m.maxHealth) m.health = m.maxHealth; + m.displayHealth(); + } + }, + do() { + if (this.lockedOn && this.lockedOn.alive) { + this.force = Vector.mult(Vector.normalise(Vector.sub(this.lockedOn.position, this.position)), this.mass * this.thrust) + } else { + if (!(simulation.cycle % this.lookFrequency)) { //find mob targets + this.closestTarget = null; + this.lockedOn = null; + let closeDist = Infinity; + for (let i = 0, len = mob.length; i < len; ++i) { + if (mob[i].dropPowerUp && Matter.Query.ray(map, this.position, mob[i].position).length === 0) { + const targetVector = Vector.sub(this.position, mob[i].position) + const dist = Vector.magnitude(targetVector) * (Math.random() + 0.5); + if (dist < closeDist) { + this.closestTarget = mob[i].position; + closeDist = dist; + this.lockedOn = mob[i] + if (0.3 > Math.random()) break //doesn't always target the closest mob + } } } } - } - if (tech.isSporeFollow && this.lockedOn === null) { //move towards player - //checking for null means that the spores don't go after the player until it has looked and not found a target - const dx = this.position.x - m.pos.x; - const dy = this.position.y - m.pos.y; - if (dx * dx + dy * dy > 10000) { - this.force = Vector.mult(Vector.normalise(Vector.sub(m.pos, Vector.add(this.playerOffPosition, this.position))), this.mass * this.thrust) + if (tech.isSporeFollow && this.lockedOn === null) { //move towards player + //checking for null means that the spores don't go after the player until it has looked and not found a target + const dx = this.position.x - m.pos.x; + const dy = this.position.y - m.pos.y; + if (dx * dx + dy * dy > 10000) { + this.force = Vector.mult(Vector.normalise(Vector.sub(m.pos, Vector.add(this.playerOffPosition, this.position))), this.mass * this.thrust) + } + } else { + this.force.y += this.mass * 0.0001; //gravity } - } else { - this.force.y += this.mass * 0.0001; //gravity + } - } + // if (!this.lockedOn && !(simulation.cycle % this.lookFrequency)) { //find mob targets + // this.closestTarget = null; + // this.lockedOn = null; + // let closeDist = Infinity; + // for (let i = 0, len = mob.length; i < len; ++i) { + // if (mob[i].dropPowerUp && Matter.Query.ray(map, this.position, mob[i].position).length === 0) { + // // Matter.Query.ray(body, this.position, mob[i].position).length === 0 + // const targetVector = Vector.sub(this.position, mob[i].position) + // const dist = Vector.magnitude(targetVector); + // if (dist < closeDist) { + // this.closestTarget = mob[i].position; + // closeDist = dist; + // this.lockedOn = mob[i] //Vector.normalise(targetVector); + // if (0.3 > Math.random()) break //doesn't always target the closest mob + // } + // } + // } + // } + // if (this.lockedOn && this.lockedOn.alive) { //accelerate towards mobs + // this.force = Vector.mult(Vector.normalise(Vector.sub(this.lockedOn.position, this.position)), this.mass * this.thrust) + // } else if (tech.isSporeFollow && this.lockedOn !== undefined) { //move towards player + // //checking for undefined means that the spores don't go after the player until it has looked and not found a target + // const dx = this.position.x - m.pos.x; + // const dy = this.position.y - m.pos.y; + // if (dx * dx + dy * dy > 10000) { + // this.force = Vector.mult(Vector.normalise(Vector.sub(m.pos, Vector.add(this.playerOffPosition, this.position))), this.mass * this.thrust) + // } + // // this.force = Vector.mult(Vector.normalise(Vector.sub(m.pos, this.position)), this.mass * this.thrust) + // } else { + // this.force.y += this.mass * 0.0001; //gravity + // } - // if (!this.lockedOn && !(simulation.cycle % this.lookFrequency)) { //find mob targets - // this.closestTarget = null; - // this.lockedOn = null; - // let closeDist = Infinity; - // for (let i = 0, len = mob.length; i < len; ++i) { - // if (mob[i].dropPowerUp && Matter.Query.ray(map, this.position, mob[i].position).length === 0) { - // // Matter.Query.ray(body, this.position, mob[i].position).length === 0 - // const targetVector = Vector.sub(this.position, mob[i].position) - // const dist = Vector.magnitude(targetVector); - // if (dist < closeDist) { - // this.closestTarget = mob[i].position; - // closeDist = dist; - // this.lockedOn = mob[i] //Vector.normalise(targetVector); - // if (0.3 > Math.random()) break //doesn't always target the closest mob - // } - // } - // } - // } - // if (this.lockedOn && this.lockedOn.alive) { //accelerate towards mobs - // this.force = Vector.mult(Vector.normalise(Vector.sub(this.lockedOn.position, this.position)), this.mass * this.thrust) - // } else if (tech.isSporeFollow && this.lockedOn !== undefined) { //move towards player - // //checking for undefined means that the spores don't go after the player until it has looked and not found a target - // const dx = this.position.x - m.pos.x; - // const dy = this.position.y - m.pos.y; - // if (dx * dx + dy * dy > 10000) { - // this.force = Vector.mult(Vector.normalise(Vector.sub(m.pos, Vector.add(this.playerOffPosition, this.position))), this.mass * this.thrust) - // } - // // this.force = Vector.mult(Vector.normalise(Vector.sub(m.pos, this.position)), this.mass * this.thrust) - // } else { - // this.force.y += this.mass * 0.0001; //gravity - // } - }, - }); - const SPEED = 4 + 8 * Math.random(); - const ANGLE = 2 * Math.PI * Math.random() - Matter.Body.setVelocity(bullet[bIndex], { - x: SPEED * Math.cos(ANGLE), - y: SPEED * Math.sin(ANGLE) - }); - World.add(engine.world, bullet[bIndex]); //add bullet to world + }, + }); - if (tech.isMutualism && m.health > 0.02) { - m.health -= 0.005 - m.displayHealth(); - bullet[bIndex].isMutualismActive = true + const SPEED = 4 + 8 * Math.random(); + const ANGLE = 2 * Math.PI * Math.random() + Matter.Body.setVelocity(bullet[bIndex], { + x: SPEED * Math.cos(ANGLE), + y: SPEED * Math.sin(ANGLE) + }); + World.add(engine.world, bullet[bIndex]); //add bullet to world + + if (tech.isMutualism && m.health > 0.02) { + m.health -= 0.005 + m.displayHealth(); + bullet[bIndex].isMutualismActive = true + } } }, iceIX(speed = 0, spread = 2 * Math.PI) { @@ -3405,6 +3408,7 @@ const b = { const me = bullet.length; const dir = m.angle + 0.02 * (Math.random() - 0.5) bullet[me] = Bodies.rectangle(m.pos.x + 35 * Math.cos(m.angle), m.pos.y + 35 * Math.sin(m.angle), 45, 20, b.fireAttributes(dir)); + Matter.Body.setDensity(bullet[me], 0.004); World.add(engine.world, bullet[me]); //add bullet to world const SPEED = (m.crouch ? 52 : 43) + Math.random() * 7 diff --git a/js/level.js b/js/level.js index 205a2d9..bfdce9c 100644 --- a/js/level.js +++ b/js/level.js @@ -16,7 +16,7 @@ const level = { // simulation.zoomScale = 1000; // simulation.setZoom(); // m.setField("nano-scale manufacturing") - // b.giveGuns("laser") + // b.giveGuns("shotgun") // tech.isExplodeRadio = true // for (let i = 0; i < 1; i++) tech.giveTech("dynamo-bot") // tech.giveTech("supercritical fission") @@ -55,6 +55,8 @@ const level = { // level.detours() //fan level // level.basement(); //fan level // level.stronghold() //fan level + // level.testChamber2() //fan level + // powerUps.directSpawn(simulation.mouseInGame.x, simulation.mouseInGame.y, "tech"); // tech.giveTech("undefined") @@ -768,7 +770,7 @@ const level = { mapB.portalPair = mapA return [portalA, portalB, mapA, mapB] }, - hazard(x, y, width, height, damage = 0.003, color = "hsla(160, 100%, 35%,0.75)", isOptical = false) { + hazard(x, y, width, height, damage = 0.003, color = "hsla(160, 100%, 35%,0.75)") { return { min: { x: x, @@ -782,15 +784,30 @@ const level = { height: height, maxHeight: height, isOn: true, + opticalQuery() { + if (this.isOn && this.height > 0 && Matter.Query.region([player], this).length && !(m.isCloak)) { + if (m.immuneCycle < m.cycle) { + m.immuneCycle = m.cycle + tech.collisionImmuneCycles; + m.damage(damage) + simulation.drawList.push({ //add dmg to draw queue + x: player.position.x, + y: player.position.y, + radius: damage * 1500, + color: simulation.mobDmgColor, + time: 20 + }); + } + } + }, query() { - if (this.isOn && this.height > 0 && Matter.Query.region([player], this).length && !(m.isCloak && isOptical)) { + if (this.isOn && this.height > 0 && Matter.Query.region([player], this).length) { const drain = 0.003 + m.fieldRegen if (m.energy > drain) { m.energy -= drain } else { if (damage < 0.02) { m.damage(damage) - } else if (m.immuneCycle < m.cycle + tech.collisionImmuneCycles) { + } else if (m.immuneCycle < m.cycle) { m.immuneCycle = m.cycle + tech.collisionImmuneCycles; m.damage(damage) simulation.drawList.push({ //add dmg to draw queue @@ -802,29 +819,24 @@ const level = { }); } } - //float - if (!isOptical) { - if (player.velocity.y > 3) player.force.y -= 0.96 * player.mass * simulation.g - const slowY = (player.velocity.y > 0) ? Math.max(0.3, 1 - 0.0015 * player.velocity.y * player.velocity.y) : Math.max(0.98, 1 - 0.001 * Math.abs(player.velocity.y)) //down : up - Matter.Body.setVelocity(player, { - x: Math.max(0.6, 1 - 0.07 * Math.abs(player.velocity.x)) * player.velocity.x, - y: slowY * player.velocity.y - }); - } + if (player.velocity.y > 5) player.force.y -= 0.95 * player.mass * simulation.g + const slowY = (player.velocity.y > 0) ? Math.max(0.4, 1 - 0.001 * player.velocity.y * player.velocity.y) : Math.max(0.98, 1 - 0.001 * Math.abs(player.velocity.y)) //down : up + Matter.Body.setVelocity(player, { + x: Math.max(0.6, 1 - 0.07 * Math.abs(player.velocity.x)) * player.velocity.x, + y: slowY * player.velocity.y + }); } //float power ups - if (!isOptical) { - powerUpCollide = Matter.Query.region(powerUp, this) - for (let i = 0, len = powerUpCollide.length; i < len; i++) { - const diameter = 2 * powerUpCollide[i].size - const buoyancy = 1 - 0.2 * Math.max(0, Math.min(diameter, this.min.y - powerUpCollide[i].position.y + powerUpCollide[i].size)) / diameter - powerUpCollide[i].force.y -= buoyancy * 1.1 * powerUpCollide[i].mass * simulation.g; - Matter.Body.setVelocity(powerUpCollide[i], { - x: powerUpCollide[i].velocity.x, - y: 0.95 * powerUpCollide[i].velocity.y - }); - } + powerUpCollide = Matter.Query.region(powerUp, this) + for (let i = 0, len = powerUpCollide.length; i < len; i++) { + const diameter = 2 * powerUpCollide[i].size + const buoyancy = 1 - 0.2 * Math.max(0, Math.min(diameter, this.min.y - powerUpCollide[i].position.y + powerUpCollide[i].size)) / diameter + powerUpCollide[i].force.y -= buoyancy * 1.1 * powerUpCollide[i].mass * simulation.g; + Matter.Body.setVelocity(powerUpCollide[i], { + x: powerUpCollide[i].velocity.x, + y: 0.95 * powerUpCollide[i].velocity.y + }); } }, draw() { @@ -1117,9 +1129,9 @@ const level = { }; level.customTopLayer = () => {}; level.setPosToSpawn(0, -50); //normal spawn - spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); level.exit.x = 1500; level.exit.y = -1875; + spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); level.defaultZoom = 1800 simulation.zoomTransition(level.defaultZoom) document.body.style.backgroundColor = "#dcdcde"; @@ -1482,8 +1494,8 @@ const level = { spawn.mapRect(1225, -1955, 175, 30); const removeIndex2 = map.length - 1 //so much work to catch blocks caught at the bottom of the vertical portals - const hazard = level.hazard(350, -2025, 700, 10, 0.4, "hsl(0, 100%, 50%)", true) //laser - const hazard2 = level.hazard(1775, -2550, 150, 10, 0.4, "hsl(0, 100%, 50%)", true) //laser + const hazard = level.hazard(350, -2025, 700, 10, 0.4, "hsl(0, 100%, 50%)") //laser + const hazard2 = level.hazard(1775, -2550, 150, 10, 0.4, "hsl(0, 100%, 50%)") //laser const button = level.button(2100, -2600) @@ -1533,8 +1545,8 @@ const level = { portal2[3].query() portal3[2].query() portal3[3].query() - hazard.query(); - hazard2.query(); + hazard.opticalQuery(); + hazard2.opticalQuery(); if (button.isUp) { hazard.isOn = false; hazard2.isOn = false; @@ -2971,6 +2983,42 @@ const level = { }); World.add(engine.world, cons[cons.length - 1]); + + + + // spawn.bodyRect(-2775, 1300, 400, 100, 1); //hoist + // cons[cons.length] = Constraint.create({ + // pointA: { + // x: -2375, + // y: 150 + // }, + // bodyB: body[body.length - 1], + // pointB: { + // x: 190, + // y: -50 + // }, + // stiffness: 0.0001, + // damping: 0.2, + // length: 1 + // }); + // cons[cons.length] = Constraint.create({ + // pointA: { + // x: -2775, + // y: 150 + // }, + // bodyB: body[body.length - 1], + // pointB: { + // x: -190, + // y: -50 + // }, + // stiffness: 0.0001, + // damping: 0.2, + // length: 1 + // }); + // World.add(engine.world, [cons[cons.length - 1], cons[cons.length - 2]]); + + + //blocks spawn.bodyRect(-165, -150, 30, 35, 1); spawn.bodyRect(-165, -115, 30, 35, 1); @@ -4019,7 +4067,7 @@ const level = { // // tether ball // spawn.tetherBoss(8000, 630, { x: 8550, y: 680 }) // let me = mob[mob.length - 1]; - // me.onDeath = function() { + // me.onDeath = function() { //please don't edit the onDeath function this causes serious bugs // this.removeCons(); //remove constraint // spawnCouloirEnHaut() // doorSortieSalle.isOpen = false; @@ -4033,7 +4081,7 @@ const level = { if (mob[i].isBoss) me = mob[i] } if (me) { - me.onDeath = function() { + me.onDeath = function() { //please don't edit the onDeath function this causes serious bugs spawnCouloirEnHaut() doorSortieSalle.isOpen = false; }; @@ -4049,7 +4097,7 @@ const level = { if (mob[i].isBoss) me = mob[i] } if (me) { - me.onDeath = function() { + me.onDeath = function() { //please don't edit the onDeath function this causes serious bugs spawnCouloirEnHaut() doorSortieSalle.isOpen = false; }; @@ -4624,5 +4672,247 @@ const level = { spawn.randomLevelBoss(3100, -1850, ["shooterBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss", "snakeBoss", "laserBoss"]); } } - } + }, + testChamber2() { + level.setPosToSpawn(-600, 400); + spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); + level.exit.x = 550; + level.exit.y = -2730; + spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20); + + const portal = level.portal({ //main portals + x: -1000, + y: 50 + }, -Math.PI / 2, { //up + x: 1000, + y: 50 + }, -Math.PI / 2) //up + const portal2 = level.portal({ //portals in upper right corner + x: 1400, + y: -2200 + }, -Math.PI / 2, { //up + x: 1700, + y: -1700 + }, -Math.PI / 2) //up + const rotor = level.rotor(-200, -1950, -0.001) + + level.custom = () => { + level.playerExitCheck(); + + portal[2].query() + portal[3].query() + portal2[2].query() + portal2[3].query() + rotor.rotate(); + }; + + level.customTopLayer = () => { + portal[0].draw(); + portal[1].draw(); + portal[2].draw(); + portal[3].draw(); + portal2[0].draw(); + portal2[1].draw(); + portal2[2].draw(); + portal2[3].draw(); + }; + + level.defaultZoom = 1700 // 4500 // 1400 + simulation.zoomTransition(level.defaultZoom) + + //section 1: before portals + spawn.mapRect(-925, 450, 1850, 250); //1-1 base + spawn.mapRect(-925, -300, 55, 755); //1 left wall + spawn.mapRect(-875, 50, 1100, 50); //1-1 ceiling + spawn.mapRect(620, -300, 305, 755); //1-1 and 1-2 right wall + spawn.bodyRect(200, 350, 230, 100); + spawn.bodyRect(300, 250, 150, 100); + spawn.mapRect(-875, -300, 580, 50); //1-2 ceiling on left + spawn.mapRect(0, -300, 625, 50); //1-2 ceiling on right + spawn.mapRect(0, -650, 150, 350); //1-3 right wall + spawn.mapRect(-925, -650, 975, 150); //1-3 ceiling + spawn.mapRect(-1280, 100, 205, 150); //1-4 floor + spawn.mapRect(-1280, 245, 360, 455); //bottom left corner + spawn.mapRect(-1600, -200, 200, 50); //1-4 platform 1 + level.fill.push({ + x: -875, + y: -250, + width: 1500, + height: 700, + color: "rgba(0,0,0,0.1)" + }); + level.fill.push({ + x: -925, + y: -505, + width: 930, + height: 255, + color: "rgba(0,0,0,0.1)" + }); + + //section 2: lower central room (gone through main portals 1 time) + spawn.mapRect(920, 245, 160, 455); //below right portal + spawn.mapRect(1075, -300, 500, 1000); //2-1 right floor + spawn.mapRect(1075, -2005, 550, 1055); //shute right wall + spawn.mapRect(875, -1000, 50, 300); //shute left 1 + spawn.mapRect(860, -1030, 50, 300); //shute left 2 + spawn.mapRect(850, -1100, 50, 300); //shute left 3 + spawn.mapRect(830, -980, 50, 50); //shute left 4 + spawn.mapRect(1075, -1000, 50, 300); //shute right 1 + spawn.mapRect(1090, -1030, 50, 300); //shute right 2 + spawn.mapRect(1100, -1100, 50, 300); //shute right 3 + spawn.mapRect(1120, -980, 50, 50); //shute right 4 + spawn.bodyRect(100, -1000, 50, 350); + spawn.bodyRect(100, -1015, 250, 15); + spawn.mapRect(-925, -1600, 100, 1000); //2-2 left wall + spawn.mapRect(725, -2150, 200, 750); //2-2 right wall + spawn.mapRect(725, -1200, 200, 200); //2-2 right wall 2 + spawn.mapRect(300, -1000, 625, 50); //2 central ledge + level.fill.push({ + x: 725, + y: -1400, + width: 200, + height: 200, + color: "rgba(0,0,0,0.1)" + }); + level.fill.push({ + x: 925, + y: -2150, + width: 150, + height: 2175, + color: "rgba(0,0,0,0.1)" + }); + level.fill.push({ + x: 925, + y: -3450, + width: 150, + height: 900, + color: "rgba(0,0,0,0.1)" + }); + + //section 3: upper left room and upper central room (gone through main portals 2 times) + spawn.mapRect(-1775, -1000, 700, 300); //3-1 floor + spawn.mapRect(-1900, -2300, 175, 1600); //3-1 left wall + spawn.mapRect(-1375, -1300, 300, 50); //3-1 platform 1 + spawn.mapRect(-1600, -1650, 300, 50); //3-1 platform 2 + spawn.mapRect(-1775, -2300, 700, 300); //3-1 ceiling + spawn.mapRect(-830, -1600, 300, 50); //2 upper left ledge + spawn.mapRect(250, -2150, 675, 50); //2 upper right ledge + spawn.mapRect(-925, -2300, 100, 400); //3-2 left wall + spawn.mapRect(-600, -2700, 1525, 150); //3-2 ceiling + spawn.mapRect(1075, -2150, 250, 150); //next to upper portal + level.fill.push({ + x: -1730, + y: -2300, + width: 870, + height: 1600, + color: "rgba(0,0,0,0.1)" + }); + + //section 4: upper right portals + spawn.mapRect(1475, -2700, 150, 700); //4-1 left wall + spawn.mapRect(1775, -1650, 250, 150); //4-1 floor-ish + spawn.mapRect(1575, -1505, 450, 555); //below upper right portal + spawn.mapRect(1800, -2250, 400, 50); //4-1 platform 2 + spawn.bodyRect(2200, -2250, 25, 300); + spawn.mapRect(2200, -1950, 400, 50); //4-1 platform 1 + //spawn.bodyRect(2575, -2600, 25, 650); + spawn.mapRect(2600, -1650, 400, 50); //4-1 platform 0 + spawn.mapRect(2200, -1350, 400, 50); //4-1 platform -1 + spawn.bodyRect(2200, -1900, 25, 550); + spawn.bodyRect(2575, -1650, 25, 300); + + spawn.mapRect(1780, -4200, 820, 1600); //top right corner + spawn.mapRect(800, -4200, 1800, -500); //4-2 ceiling + spawn.mapRect(1075, -3450, 250, 900); //4-2 center block + spawn.mapRect(800, -3450, 125, 900); //4-2 left wall + spawn.mapRect(1550, -4200, 310, 600); //4-2 upper right wall + level.fill.push({ + x: 1800, + y: -2200, + width: 225, + height: 550, + color: "rgba(0,0,0,0.1)" + }); + level.fill.push({ + x: 1800, + y: -2600, + width: 400, + height: 400, + color: "rgba(0,0,0,0.1)" + }); + level.fill.push({ + x: 2200, + y: -2600, + width: 400, + height: 1250, + color: "rgba(0,0,0,0.1)" + }); + + //section 5: after portals (gone through main portals 3 times) + spawn.mapRect(-700, -2700, 100, 450); //5-1 right wall + spawn.mapRect(-1450, -2700, 900, 50); //5-1 ceiling + spawn.mapRect(-925, -2300, 325, 50); //5-1 right floor + level.fill.push({ + x: -1450, + y: -2655, + width: 755, + height: 355, + color: "rgba(0,0,0,0.1)" + }); + + //top left corner stuff + if (true) { + spawn.mapRect(-1900, -2450, 250, 450); // + } else { + spawn.boost(-1650, -2310, 400); + spawn.mapRect(-2200, -2700, 450, 50); // + spawn.mapRect(-1850, -3000, 500, 50); // + } + + //exit room + spawn.mapRect(350, -3000, 50, 100); //exit room left wall + spawn.mapRect(350, -3000, 450, -1700); //exit room ceiling + spawn.bodyRect(350, -2900, 50, 50); //door + spawn.bodyRect(350, -2850, 50, 50); //door + spawn.bodyRect(350, -2800, 50, 50); //door + spawn.bodyRect(350, -2750, 50, 50); //door + level.fillBG.push({ + x: 375, + y: -3000, + width: 450, + height: 300, + color: "#d4f4f4" + }); + + spawn.debris(-800, -50, 400, 6); //16 debris per level + spawn.debris(-1650, -2300, 250, 4); //16 debris per level + spawn.debris(-750, -650, 750, 6); //16 debris per level + + //mobs + spawn.randomMob(-650, -100, 0.7); //1-2 left + spawn.randomMob(100, -150, 0.3); //1-2 right + spawn.randomMob(-100, -400, 0); //1-3 right + //spawn.randomMob(-1500, -300, 0.3); //1-4 platform + spawn.randomMob(1450, -450, 0); //2-1 right + spawn.randomMob(1700, -800, 1); //2-1 off the edge. chance is 1 because some enemies just fall + spawn.randomGroup(-550, -1000, -0.3); //2-2 + spawn.randomMob(-1550, -1800, 0.7); //3-1 upper platform + //spawn.randomMob(-1225, -1400, 0.3); //3-1 lower platform + spawn.randomMob(450, -2350, 0.3); //3-2 right ledge + //spawn.randomMob(1150, -2250, 0); //3-2 far right + spawn.randomGroup(2400, -2300, -0.3); //4-1 floating + spawn.randomMob(2400, -1450, 0); //4-1 platform -1 + spawn.randomMob(2800, -1800, 0.5); //4-1 platform 0 + spawn.randomMob(-1100, -2800, 0.5); //5-2 left + spawn.randomMob(-550, -2800, 0.5); //5-2 middle + if (simulation.difficulty > 3) { + if (Math.random() < 0.5) { + spawn.randomLevelBoss(450, -1350, ["shooterBoss", "launcherBoss", "laserTargetingBoss", "streamBoss", "shieldingBoss", "pulsarBoss", "laserBoss"]); + } else { + spawn.randomLevelBoss(-300, -3200, ["shooterBoss", "launcherBoss", "laserTargetingBoss", "streamBoss", "shieldingBoss", "pulsarBoss", "laserBoss"]); + } + } + powerUps.addRerollToLevel() //needs to run after mobs are spawned + if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(7725, 2275); + }, }; \ No newline at end of file diff --git a/js/player.js b/js/player.js index 78b6258..6575a3d 100644 --- a/js/player.js +++ b/js/player.js @@ -647,7 +647,6 @@ const m = { m.energy -= dmg; if (m.energy < 0 || isNaN(m.energy)) { //taking deadly damage if (tech.isDeathAvoid && powerUps.research.count && !tech.isDeathAvoidedThisLevel) { - tech.isDeathAvoidedThisLevel = true powerUps.research.changeRerolls(-1) simulation.makeTextLog(`m.research--
${powerUps.research.count}`) diff --git a/js/powerup.js b/js/powerup.js index 4f5ba6d..c2c5668 100644 --- a/js/powerup.js +++ b/js/powerup.js @@ -112,11 +112,6 @@ const powerUps = { document.getElementById("tech-anthropic").innerHTML = `-${powerUps.research.count}` } if (tech.renormalization && Math.random() < 0.37 && amount < 0) powerUps.spawn(m.pos.x, m.pos.y, "research"); - if (tech.isResearchReality && amount < 0) { - m.switchWorlds() - simulation.trails() - simulation.makeTextLog(`simulation.amplitude = ${Math.random()}`); - } if (tech.isRerollHaste) { if (powerUps.research.count === 0) { tech.researchHaste = 0.66; @@ -141,6 +136,11 @@ const powerUps = { // simulation.makeTextLog(`${Math.max(0,powerUps.tech.lastTotalChoices - powerUps.tech.banishLog.length)} estimated tech choices remaining`) simulation.makeTextLog(`powerUps.tech.length: ${Math.max(0,powerUps.tech.lastTotalChoices - powerUps.tech.banishLog.length)}`) } + if (tech.isResearchReality) { + m.switchWorlds() + simulation.trails() + simulation.makeTextLog(`simulation.amplitude = ${Math.random()}`); + } powerUps[type].effect(); }, }, diff --git a/js/simulation.js b/js/simulation.js index dd0dc5c..d940daf 100644 --- a/js/simulation.js +++ b/js/simulation.js @@ -525,7 +525,9 @@ const simulation = { level.levels.push("basement"); level.levels.push("detours"); level.levels.push("house"); - level.levels.splice(0, 4); //remove 4 random levels to make up for adding the 4 community levels + level.levels.push("testChamber2"); + // level.levels.push("vats"); + level.levels.splice(0, 5); //remove some random levels to make up for adding the community levels } level.levels = shuffle(level.levels); //shuffles order of maps level.levels.unshift("intro"); //add level to the start of the randomized levels list @@ -699,6 +701,7 @@ const simulation = { let holdTarget; //if player is holding something this remembers it before it gets deleted if (m.holdingTarget) holdTarget = m.holdingTarget; + simulation.fallHeight = 3000; m.fireCDcycle = 0 m.drop(); m.hole.isOn = false; @@ -993,6 +996,7 @@ const simulation = { for (let i = 0, len = cons.length; i < len; ++i) { ctx.moveTo(cons[i].pointA.x, cons[i].pointA.y); ctx.lineTo(cons[i].bodyB.position.x, cons[i].bodyB.position.y); + // ctx.lineTo(cons[i].bodyB.position.x + cons[i].pointB.x, cons[i].bodyB.position.y + cons[i].pointB.y); } for (let i = 0, len = consBB.length; i < len; ++i) { ctx.moveTo(consBB[i].bodyA.position.x, consBB[i].bodyA.position.y); diff --git a/js/spawn.js b/js/spawn.js index 6b3428f..386c57e 100644 --- a/js/spawn.js +++ b/js/spawn.js @@ -1579,7 +1579,7 @@ const spawn = { } }; }, - pulsar(x, y, radius = 30) { + pulsar(x, y, radius = 40) { mobs.spawn(x, y, 3, radius, "#f08"); let me = mob[mob.length - 1]; me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front @@ -1587,10 +1587,11 @@ const spawn = { me.radius *= 2 me.vertices[1].x = me.position.x + Math.cos(me.angle) * me.radius; //make one end of the triangle longer me.vertices[1].y = me.position.y + Math.sin(me.angle) * me.radius; - me.fireCycle = 0 + Matter.Body.setDensity(me, 0.002); //extra dense //normal is 0.001 //makes effective life much larger + me.fireCycle = Infinity me.fireTarget = { x: 0, y: 0 } - me.pulseRadius = Math.min(400, 150 + simulation.difficulty * 3) - me.fireDelay = Math.max(70, 180 - simulation.difficulty) + me.pulseRadius = Math.min(400, 165 + simulation.difficulty * 3) + me.fireDelay = Math.max(75, 150 - simulation.difficulty * 0.5) me.isFiring = false me.onHit = function() {}; me.canSeeTarget = function() { @@ -1681,7 +1682,7 @@ const spawn = { this.torque += 0.000001 * this.inertia; } else if (dot < -threshold) { this.torque -= 0.000001 * this.inertia; - } else if (this.fireCycle > 90) { // aim + } else if (this.fireCycle > 60) { // aim unit = Vector.mult(Vector.normalise(Vector.sub(this.vertices[1], this.position)), this.distanceToPlayer() - 100) this.fireTarget = Vector.add(this.vertices[1], unit) if (!this.canSeeTarget()) return diff --git a/js/tech.js b/js/tech.js index a763c8e..97cf91a 100644 --- a/js/tech.js +++ b/js/tech.js @@ -67,7 +67,7 @@ if (index === 'random') { let options = []; for (let i = 0; i < tech.tech.length; i++) { - if (tech.tech[i].count < tech.tech[i].maxCount && tech.tech[i].allowed()) options.push(i); + if (tech.tech[i].count < tech.tech[i].maxCount && tech.tech[i].allowed() && !tech.tech[i].isJunk && !tech.tech[i].isLore) options.push(i); } // give a random tech from the tech I don't have if (options.length > 0) { @@ -86,6 +86,12 @@ } if (!found) return //if name not found don't give any tech } + if (tech.isMetaAnalysis && tech.tech[index].isJunk) { + tech.giveTech('random', true) + for (let i = 0; i < 2; i++) powerUps.spawn(m.pos.x + 10 * Math.random(), m.pos.y + 10 * Math.random(), "research"); + return + } + if (tech.tech[index].isLost) tech.tech[index].isLost = false; //give specific tech tech.tech[index].effect(); //give specific tech tech.tech[index].count++ @@ -1176,8 +1182,8 @@ tech.isBotDamage = false } }, { - name: "bot replication", - description: "duplicate your permanent bots
remove all of your guns", + name: "ersatz bots", + description: "double your permanent bots
remove all of your guns", maxCount: 1, count: 0, frequency: 1, @@ -2000,7 +2006,7 @@ frequency: 1, isHealTech: true, allowed() { - return m.maxHealth > 1 || tech.isArmorFromPowerUps + return m.health > 0.1 && (m.maxHealth > 1 || tech.isArmorFromPowerUps) }, requires: "increased max health", effect() { @@ -2134,9 +2140,9 @@ count: 0, frequency: 1, allowed() { - return !tech.isImmortal && !tech.isResearchReality + return !tech.isImmortal && !tech.isResearchReality && level.onLevel < 6 }, - requires: "not quantum immortality, perturbation theory", + requires: "before level 6, not quantum immortality, perturbation theory", effect() { tech.isSwitchReality = true; }, @@ -2150,9 +2156,9 @@ count: 0, frequency: 1, allowed() { - return !tech.isImmortal && !tech.isSwitchReality + return !tech.isImmortal && !tech.isSwitchReality && (powerUps.research.count > 2 || build.isExperimentSelection) }, - requires: "not quantum immortality, many-worlds", + requires: "at least 2 research, not quantum immortality, many-worlds", effect() { tech.isResearchReality = true; for (let i = 0; i < 11; i++) powerUps.spawn(m.pos.x + Math.random() * 10, m.pos.y + Math.random() * 10, "research", false); @@ -2167,9 +2173,9 @@ count: 0, frequency: 1, allowed() { - return (powerUps.research.count > 1 || build.isExperimentSelection) && !tech.isSuperDeterminism && !tech.isRerollHaste + return (powerUps.research.count > 2 || build.isExperimentSelection) && !tech.isSuperDeterminism && !tech.isRerollHaste }, - requires: "not superdeterminism or Ψ(t) collapse
at least 2 research", + requires: "not superdeterminism or Ψ(t) collapse
at least 3 research", effect() { tech.renormalization = true; }, @@ -2313,26 +2319,25 @@ remove() { tech.isShieldAmmo = false; } - }, { - name: "stimulated emission", - description: "20% chance to duplicate spawned power ups
but, after a collision eject 1 tech", + }, + { + name: "meta-analysis", + description: "if you choose a junk tech you instead get a
random non-junk tech and spawn 2 research", maxCount: 1, count: 0, - frequency: 1, + frequency: 2, allowed() { - return tech.duplicationChance() < 1 + return tech.duplicateChance }, - requires: "below 100% duplication chance", - effect: () => { - tech.isBayesian = true - simulation.draw.powerUp = simulation.draw.powerUpBonus //change power up draw - tech.maxDuplicationEvent() + requires: "replication", + effect() { + tech.isMetaAnalysis = true }, remove() { - tech.isBayesian = false - if (tech.duplicationChance() === 0) simulation.draw.powerUp = simulation.draw.powerUpNormal + tech.isMetaAnalysis = false } - }, { + }, + { name: "replication", description: "7% chance to duplicate spawned power ups
add 12 junk tech to the potential pool", maxCount: 9, @@ -2354,7 +2359,28 @@ if (tech.duplicationChance() === 0) simulation.draw.powerUp = simulation.draw.powerUpNormal if (this.count > 1) tech.removeJunkTechFromPool(12) } - }, { + }, + { + name: "stimulated emission", + description: "20% chance to duplicate spawned power ups
but, after a collision eject 1 tech", + maxCount: 1, + count: 0, + frequency: 1, + allowed() { + return tech.duplicationChance() < 1 + }, + requires: "below 100% duplication chance", + effect: () => { + tech.isBayesian = true + simulation.draw.powerUp = simulation.draw.powerUpBonus //change power up draw + tech.maxDuplicationEvent() + }, + remove() { + tech.isBayesian = false + if (tech.duplicationChance() === 0) simulation.draw.powerUp = simulation.draw.powerUpNormal + } + }, + { name: "futures exchange", description: "clicking × to cancel a field, tech, or gun
adds 4.5% power up duplication chance", maxCount: 1, @@ -2682,27 +2708,6 @@ tech.isSuperDeterminism = false; } }, - // { - // name: "ammo technology", - // description: "double the frequency of finding gun tech
spawn 6 ammo", - // maxCount: 1, - // count: 0, - // frequency: 1, - // isNonRefundable: true, - // // isExperimentHide: true, - // // isBadRandomOption: true, - // allowed() { - // return !tech.isEnergyNoAmmo - // }, - // requires: "not exciton lattice", - // effect() { - // for (let i = 0; i < 6; i++) powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "ammo"); - // for (let i = 0, len = tech.tech.length; i < len; i++) { - // if (tech.tech[i].isGunTech) tech.tech[i].frequency *= 2 - // } - // }, - // remove() {} - // }, //************************************************** //************************************************** gun //************************************************** tech @@ -4352,23 +4357,6 @@ // } // }, { - name: "plasma jet", - description: "increase plasma torch's range by 27%", - isFieldTech: true, - maxCount: 9, - count: 0, - frequency: 1, - allowed() { - return m.fieldUpgrades[m.fieldMode].name === "plasma torch" - }, - requires: "plasma torch", - effect() { - tech.isPlasmaRange += 0.27; - }, - remove() { - tech.isPlasmaRange = 1; - } - }, { name: "plasma-bot", description: "a bot uses energy to emit plasma
that damages and pushes mobs", isFieldTech: true, @@ -4388,7 +4376,26 @@ remove() { tech.plasmaBotCount = 0; } - }, { + }, + { + name: "plasma jet", + description: "increase plasma torch's range by 30%", + isFieldTech: true, + maxCount: 9, + count: 0, + frequency: 1, + allowed() { + return m.fieldUpgrades[m.fieldMode].name === "plasma torch" && !tech.isExtruder + }, + requires: "plasma torch, not micro-extruder", + effect() { + tech.isPlasmaRange += 0.3; + }, + remove() { + tech.isPlasmaRange = 1; + } + }, + { name: "micro-extruder", description: "plasma torch extrudes a thin hot wire
increases damage, and energy drain", isFieldTech: true, @@ -4396,9 +4403,9 @@ count: 0, frequency: 1, allowed() { - return m.fieldUpgrades[m.fieldMode].name === "plasma torch" + return m.fieldUpgrades[m.fieldMode].name === "plasma torch" && tech.isPlasmaRange === 1 }, - requires: "plasma torch", + requires: "plasma torch, not plasma jet", effect() { tech.isExtruder = true; }, @@ -5790,5 +5797,6 @@ isFlipFlopOn: null, isFlipFlopLevelReset: null, isFlipFlopDamage: null, - isFlipFlopEnergy: null + isFlipFlopEnergy: null, + isMetaAnalysis: null } \ No newline at end of file diff --git a/todo.txt b/todo.txt index 84bd6d1..f644ede 100644 --- a/todo.txt +++ b/todo.txt @@ -1,29 +1,19 @@ ******************************************************** NEXT PATCH ******************************************************** +meta-analysis - if you choose a junk tech you instead get a random tech and spawn 2 research +micro-extruder should have 50% less lag + +new community level testChamber2! by Oranger on n-gon discord +(be sure to enable community levels in settings) ******************************************************** BUGS ******************************************************** -inductive + MEE + 1st ion + negentrophy + electrolytes + tranceiver chip + dupe chance is ridiculously op - -micro-extruder is laggy? +fix issue where you have to press z once to get copy to work for simulation.enableConstructMode() mouse event e.which is deprecated fix door.isOpen actually meaning isClosed? -(once for me, and a few times for discord) player gets stuck in crouch animation - occurred after rerolling a power up (which triggered a switchWorlds) - can't jump, move slow - m.crouch = false - only fixed itself when you click fire (drones, so no recoil) - fire fixes: - if (m.holdingTarget) m.drop() - so probably the player is getting stuck holding a block, but the block is removed - what removes blocks? - fixed? I added: if (m.holdingTarget) m.drop(); to powerUps.endDraft and to m.switchWorlds - -use the floor of portal sensor on the player? to unstuck player - (only once on my computer) once every 7 second check isn't running code power ups don't teleport to exit complex spin statistics isn't activating @@ -48,19 +38,19 @@ use the floor of portal sensor on the player? to unstuck player ******************************************************** TODO ******************************************************** -add a delay between each fire for pulsar mobs -mob bullets that blow up - draw outline of exploded region, 2 seconds later damage player in region and remove bullet +allow levels to adjust the teleport limit in simulation.checks -holding down the field button on fields that don't have a normal field graphic shows a field arc outline to indicate grabbing blocks +copy time-like foam to shotgun mob sniper: draw aim graphics before fire tech laser: photon - laser, but it can only move 100 pixels a cycle -mob - grows after taking damage -mob - attack outwardly after taking damage +mob - after taking damage + attack outwardly + grows + teleports tech- foam is attracted to mobs use a gravitational attraction model? @@ -78,15 +68,6 @@ mobile requirements: tap screen regions to move (WASD) reduce font size -tech: removes itself after a few levels - gives extra duplication for 2 levels, then removes all duplication - -use ship tech to make a mob mode - differences from ship to mob - graphics - take no damage from mob collision - It would be cool if you could exit mob mode - decrease healing effects by 50% decrease level scaling healing reduction net effect: healing at difficulty 40 (level 10 hard) should be 25% higher then current levels @@ -99,8 +80,6 @@ bosses should have 2x health, but only do about 50 health damage boss flag cut damage done to boss by 20x <---- make bosses not have extra density -tech: spawn a bot after taking collision damage - map: laboratory rooms with switches that change physics gravity room @@ -110,11 +89,6 @@ map: laboratory portal + rotor + falling blocks = perpetual motion room a button that spawns a heal. -copy time-like foam to other guns? - wave gun - shotgun - nail gun - lore: a tutorial / lore intro needs to be optional so it doesn't slow experienced players put something on the intro map @@ -346,6 +320,7 @@ possible names for tech genetic algorithm metaheuristic - is a higher-level procedure or heuristic designed to find, generate, or select a heuristic (partial search algorithm) that may provide a sufficiently good solution to an optimization problem, especially with incomplete or imperfect information or limited computation capacity stochastic optimization + meta-analysis plot script: