diff --git a/js/bullet.js b/js/bullet.js index 294f84a..fae5e81 100644 --- a/js/bullet.js +++ b/js/bullet.js @@ -4612,19 +4612,18 @@ const b = { this.force.y += this.mass * tech.foamGravity; //gravity if (tech.isFoamAttract) { for (let i = 0, len = mob.length; i < len; i++) { + const range = Vector.magnitude(Vector.sub(mob[i].position, this.position)) 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 && - !mob[i].isInvulnerable + !mob[i].isInvulnerable && + range < 500 && + 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 - }); + const mag = 0.001 * Math.min(1, 200 / range) + this.force = Vector.mult(Vector.normalise(Vector.sub(mob[i].position, this.position)), this.mass * mag) + const slow = 0.98 + Matter.Body.setVelocity(this, { x: this.velocity.x * slow, y: this.velocity.y * slow }); break } } @@ -7509,10 +7508,7 @@ const b = { bullet[me].do = function () { function onCollide(that) { that.collisionFilter.mask = 0; //non collide with everything - Matter.Body.setVelocity(that, { - x: 0, - y: 0 - }); + Matter.Body.setVelocity(that, { x: 0, y: 0 }); that.do = that.grow; } const mobCollisions = Matter.Query.collides(this, mob) diff --git a/js/level.js b/js/level.js index 1f9928b..208cc30 100644 --- a/js/level.js +++ b/js/level.js @@ -4,6 +4,7 @@ let cons = []; //all constraints between a point and a body let consBB = []; //all constraints between two bodies let composite = [] //rotors and other map elements that don't fit const level = { + isEndlessFall: false, defaultZoom: 1400, onLevel: -1, levelsCleared: 0, @@ -15,27 +16,27 @@ const level = { levels: [], start() { if (level.levelsCleared === 0) { //this code only runs on the first level - // simulation.enableConstructMode() //tech.giveTech('motion sickness') //used to build maps in testing mode + simulation.enableConstructMode() //tech.giveTech('motion sickness') //used to build maps in testing mode // simulation.isHorizontalFlipped = true // tech.giveTech("performance") // level.difficultyIncrease(3 * 4) //30 is near max on hard //60 is near max on why // spawn.setSpawnList(); // spawn.setSpawnList(); - // m.maxHealth = m.health = 100 + m.maxHealth = m.health = 100 // tech.isRerollDamage = true // powerUps.research.changeRerolls(99999) // m.immuneCycle = Infinity //you can't take damage // tech.tech[297].frequency = 100 // m.couplingChange(10) - // m.setField("standing wave") //1 standing wave 2 perfect diamagnetism 3 negative mass 4 molecular assembler 5 plasma torch 6 time dilation 7 metamaterial cloaking 8 pilot wave 9 wormhole + // m.setField("wormhole") //1 standing wave 2 perfect diamagnetism 3 negative mass 4 molecular assembler 5 plasma torch 6 time dilation 7 metamaterial cloaking 8 pilot wave 9 wormhole // m.energy = 0 // simulation.molecularMode = 2 // m.damage(0.1); // b.giveGuns("super balls") //0 nail gun 1 shotgun 2 super balls 3 wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser - // b.giveGuns("drones") //0 nail gun 1 shotgun 2 super balls 3 wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser - // b.guns[3].ammo = 100000000 + // b.giveGuns("foam") //0 nail gun 1 shotgun 2 super balls 3 wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser + // b.guns[8].ammo = 100000000 // requestAnimationFrame(() => { tech.giveTech("MACHO") }); - // for (let i = 0; i < 1; ++i) tech.giveTech("additive manufacturing") + // for (let i = 0; i < 1; ++i) tech.giveTech("electrostatic induction") // for (let i = 0; i < 1; ++i) tech.giveTech("flatland") // for (let i = 0; i < 1; ++i) tech.giveTech("foam-bot") // for (let i = 0; i < 1; ++i) tech.giveTech("nail-bot") @@ -49,7 +50,7 @@ const level = { // for (let i = 0; i < 10; i++) powerUps.directSpawn(1750, -500, "research"); // for (let i = 0; i < 10; i++) powerUps.directSpawn(1750, -500, "coupling"); - // level.testing(); + level.skyscrapers(); // for (let i = 0; i < 4; ++i) spawn.hopMother(1900, -500) // for (let i = 0; i < 0; ++i) spawn.hopper(1900, -500) // for (let i = 0; i < 1; ++i) spawn.shooterBoss(1900, -2500) @@ -62,7 +63,7 @@ const level = { // spawn.tetherBoss(1900, -500, { x: 1900, y: -500 }) // for (let i = 0; i < 40; ++i) tech.giveTech() - level[simulation.isTraining ? "walk" : "intro"]() //normal starting level ************************************************** + // level[simulation.isTraining ? "walk" : "intro"]() //normal starting level ************************************************** // simulation.isAutoZoom = false; //look in close // simulation.zoomScale *= 0.5; @@ -100,7 +101,7 @@ const level = { } } if (!simulation.isTraining) level.levelAnnounce(); - simulation.noCameraScroll(); + simulation.setupCamera(player.position); simulation.setZoom(); level.addToWorld(); //add bodies to game engine simulation.draw.setPaths(); @@ -1345,10 +1346,12 @@ const level = { //teleport if (this.portalPair.angle % (Math.PI / 2)) { //if left, right up or down if (m.immuneCycle < m.cycle + m.collisionImmuneCycles) m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage for 30 cycles - Matter.Body.setPosition(player, this.portalPair.portal.position); + // Matter.Body.setPosition(player, this.portalPair.portal.position); + simulation.translatePlayerAndCamera(this.portalPair.portal.position) } else { //if at some odd angle if (m.immuneCycle < m.cycle + m.collisionImmuneCycles) m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage for 30 cycles - Matter.Body.setPosition(player, this.portalPair.position); + // Matter.Body.setPosition(player, this.portalPair.position); + simulation.translatePlayerAndCamera(this.portalPair.position) } //rotate velocity let mag @@ -5347,6 +5350,7 @@ const level = { powerUps.addResearchToLevel() //needs to run after mobs are spawned }, pavilion() { + level.isEndlessFall = true; const vanish = [] level.exit.x = -850; level.exit.y = -1485; @@ -5375,6 +5379,7 @@ const level = { vanish.push(level.vanish(-350, -450, 150, 223)) spawn.mapRect(2475, -1800, 250, 2300); + spawn.mapRect(1200, -750, 100, 450); spawn.mapRect(1200, -375, 250, 75); powerUps.spawnStartingPowerUps(550, -100); @@ -5403,7 +5408,6 @@ const level = { } // vanish.push(level.vanish(575, -1575, 375, 225)) - spawn.bodyRect(225, -850, 50, 100, 0.4); spawn.mapRect(600, -1800, 325, 225); spawn.mapRect(1900, -1500, 325, 25); @@ -5421,9 +5425,11 @@ const level = { vanish.push(level.vanish(-50, -1800, 450, 25)) //exit - spawn.mapRect(-1050, -1450, 700, 25); - spawn.mapRect(-1050, -1800, 525, 25); - spawn.mapRect(-550, -1800, 25, 200); + // spawn.mapRect(-1050, -1450, 700, 25); + // spawn.mapRect(-1050, -1800, 525, 25); + spawn.mapRect(-575, -1800, 50, 200); + spawn.mapRect(-1050, -1800, 525, 75); + spawn.mapRect(-1050, -1450, 700, 75); spawn.randomMob(-1175, -1975, -0.4); spawn.randomMob(275, -1500, -0.3); @@ -6193,6 +6199,7 @@ const level = { }, satellite() { + level.isEndlessFall = true; const boost1 = level.boost(5825, 235, 1400) const elevator = level.elevator(4210, -1265, 380, 50, -3450) //, 0.003, { up: 0.01, down: 0.2 } level.custom = () => { @@ -6368,6 +6375,8 @@ const level = { } }, rooftops() { + level.isEndlessFall = true; + // level.fallPosition = { x: 5000, y:-4000} const elevator = level.elevator(1450, -990, 235, 45, -2000) const boost1 = level.boost(4950, 0, 1100) @@ -6554,6 +6563,7 @@ const level = { } }, aerie() { + level.isEndlessFall = true; const boost1 = level.boost(-425, 100, 1400) const boost2 = level.boost(5350, 275, 2850); @@ -6782,6 +6792,7 @@ const level = { } }, skyscrapers() { + level.isEndlessFall = true; const boost1 = level.boost(475, 0, 1300) const boost2 = level.boost(4450, 0, 1300); level.custom = () => { @@ -6919,6 +6930,7 @@ const level = { } }, highrise() { + level.isEndlessFall = true; const elevator1 = level.elevator(-790, -190, 180, 25, -1150, 0.0025, { up: 0.01, down: 0.2 @@ -7203,6 +7215,7 @@ const level = { } }, warehouse() { + level.isEndlessFall = true; level.custom = () => { ctx.fillStyle = "#444" //light fixtures ctx.fillRect(-920, -505, 40, 10) @@ -18205,8 +18218,8 @@ const level = { spawn.mapRect(1350, -325, 100, 50); spawn.mapRect(1400, -1500, 325, 1600); spawn.mapRect(1400, -1500, 1550, 50); - spawn.mapRect(1400, -1900, 900, 50); - spawn.mapRect(1400, -2900, 100, 1050); + spawn.mapRect(1250, -1900, 1050, 50); + spawn.mapRect(1250, -2900, 100, 1050); spawn.mapRect(-600, -2900, 3550, 100); spawn.mapRect(2850, -2900, 100, 700); @@ -18243,6 +18256,28 @@ const level = { const piston7 = horizontalDoor(-2000, -2600, 300, 100, 300, 20); const hand1 = clockHand(400, -3700, 75, 600); const elevator1 = level.elevator(3200, 0, 150, 50, -1750, 0.0025, { up: 0.05, down: 0.2 }); + const lightButton = level.button(1400, -1900); + lightButton.isUp = true; + var lightOn = false; + simulation.ephemera.push({ + name: "lightWire", + do() { + if (level.levels[level.onLevel] == "clock") { + // light wire + ctx.beginPath(); + ctx.moveTo(1460, -1887); + ctx.lineTo(1300, -1887); + ctx.lineTo(1300, -2860); + ctx.lineTo(400, -2860); + ctx.lineTo(400, -2800); + ctx.lineWidth = 6; + ctx.strokeStyle = lightOn ? "#ffd700" : "000"; + ctx.stroke(); + } else { + simulation.removeEphemera(this.name); + } + }, + }) spawn.debris(-300, 0, 1300, 6); spawn.debris(0, -2900, 2500, 8); @@ -18299,7 +18334,7 @@ const level = { } var circleHead = Matter.Bodies.polygon(m.pos.x, m.pos.y, 0, 31); - var losDomain = generateIntersectMap().concat(mob.filter((obj) => { return obj.isNotCloaked == null && (obj.isBoss || obj.label != 'Circle Body') }), [pendulum1, gear1, gear2, piston1, player, circleHead]); + var losDomain = generateIntersectMap().concat(mob.filter((obj) => { return obj.isNotCloaked == null && (obj.isBoss || obj.label != 'Circle Body') }), [pendulum1, gear1, gear2, player, circleHead]); var oldMap = [...map]; var oldMob = [...mob]; var spawnGearMobCycle = 0; @@ -18313,12 +18348,12 @@ const level = { var startCycle = simulation.cycle; // used to offset simulation.cycle to avoid the swing starting halfway through at the start of the level and messing up syncronization level.custom = () => { - Matter.Body.setPosition(circleHead, m.pos) - if (!(compareArrays(oldMap, map) && compareArrays(oldMob, mob))) { - losDomain = generateIntersectMap().concat(mob.filter((obj) => { return obj.isNotCloaked == null && (obj.isBoss || obj.label != 'Circle Body') }), [pendulum1, gear1, gear2, piston1, player, circleHead]); + if (lightOn) { + Matter.Body.setPosition(circleHead, m.pos) + if (!(compareArrays(oldMap, map) && compareArrays(oldMob, mob))) losDomain = generateIntersectMap().concat(mob.filter((obj) => { return obj.isNotCloaked == null && (obj.isBoss || obj.label != 'Circle Body') }), [pendulum1, gear1, gear2, player, circleHead]); + oldMap = [...map]; + oldMob = [...mob]; } - oldMap = [...map]; - oldMob = [...mob]; ctx.fillStyle = "#b0b0b2"; ctx.fillRect(-600, -1700, 2000, 1700); ctx.fillRect(1350, -1851, 1550, 350); @@ -18330,39 +18365,41 @@ const level = { ctx.fillStyle = "#000"; ctx.fillRect(350, -2800, 100, 25); // light - var lightPos = { x: 400, y: -2775 }; - var lightRadius = 2950; - const vertices = circleLoS(lightPos, lightRadius, map.concat(mob.filter((obj) => { return obj.isNotCloaked == null && (obj.isBoss || obj.label != 'Circle Body') }), [pendulum1, gear1, gear2, piston1, player, circleHead])); if (vertices.length > 0 && vertices[0].x) { - ctx.beginPath(); - ctx.moveTo(vertices[0].x, vertices[0].y); - for (var i = 1; i < vertices.length; i++) { - var currentDistance = Math.sqrt((vertices[i - 1].x - lightPos.x) ** 2 + (vertices[i - 1].y - lightPos.y) ** 2); - var newDistance = Math.sqrt((vertices[i].x - lightPos.x) ** 2 + (vertices[i].y - lightPos.y) ** 2); + if (lightOn) { + var lightPos = { x: 400, y: -2775 }; + var lightRadius = 2950; + const vertices = circleLoS(lightPos, lightRadius, map.concat(mob.filter((obj) => { return obj.isNotCloaked == null && (obj.isBoss || obj.label != 'Circle Body') }), [pendulum1, gear1, gear2, player, circleHead])); if (vertices.length > 0 && vertices[0].x) { + ctx.beginPath(); + ctx.moveTo(vertices[0].x, vertices[0].y); + for (var i = 1; i < vertices.length; i++) { + var currentDistance = Math.sqrt((vertices[i - 1].x - lightPos.x) ** 2 + (vertices[i - 1].y - lightPos.y) ** 2); + var newDistance = Math.sqrt((vertices[i].x - lightPos.x) ** 2 + (vertices[i].y - lightPos.y) ** 2); + if (Math.abs(currentDistance - lightRadius) < 1 && Math.abs(newDistance - lightRadius) < 1) { + const currentAngle = Math.atan2(vertices[i - 1].y - lightPos.y, vertices[i - 1].x - lightPos.x); + const newAngle = Math.atan2(vertices[i].y - lightPos.y, vertices[i].x - lightPos.x); + ctx.arc(lightPos.x, lightPos.y, lightRadius, currentAngle, newAngle); + } else { + ctx.lineTo(vertices[i].x, vertices[i].y) + } + } + newDistance = Math.sqrt((vertices[0].x - lightPos.x) ** 2 + (vertices[0].y - lightPos.y) ** 2); + currentDistance = Math.sqrt((vertices[vertices.length - 1].x - lightPos.x) ** 2 + (vertices[vertices.length - 1].y - lightPos.y) ** 2); if (Math.abs(currentDistance - lightRadius) < 1 && Math.abs(newDistance - lightRadius) < 1) { - const currentAngle = Math.atan2(vertices[i - 1].y - lightPos.y, vertices[i - 1].x - lightPos.x); - const newAngle = Math.atan2(vertices[i].y - lightPos.y, vertices[i].x - lightPos.x); + const currentAngle = Math.atan2(vertices[vertices.length - 1].y - lightPos.y, vertices[vertices.length - 1].x - lightPos.x); + const newAngle = Math.atan2(vertices[0].y - lightPos.y, vertices[0].x - lightPos.x); ctx.arc(lightPos.x, lightPos.y, lightRadius, currentAngle, newAngle); } else { - ctx.lineTo(vertices[i].x, vertices[i].y) + ctx.lineTo(vertices[0].x, vertices[0].y) } + ctx.fillStyle = "rgba(216, 218, 223, 0.5)"; + ctx.fill(); } - newDistance = Math.sqrt((vertices[0].x - lightPos.x) ** 2 + (vertices[0].y - lightPos.y) ** 2); - currentDistance = Math.sqrt((vertices[vertices.length - 1].x - lightPos.x) ** 2 + (vertices[vertices.length - 1].y - lightPos.y) ** 2); - if (Math.abs(currentDistance - lightRadius) < 1 && Math.abs(newDistance - lightRadius) < 1) { - const currentAngle = Math.atan2(vertices[vertices.length - 1].y - lightPos.y, vertices[vertices.length - 1].x - lightPos.x); - const newAngle = Math.atan2(vertices[0].y - lightPos.y, vertices[0].x - lightPos.x); - ctx.arc(lightPos.x, lightPos.y, lightRadius, currentAngle, newAngle); - } else { - ctx.lineTo(vertices[0].x, vertices[0].y) - } - ctx.fillStyle = "rgba(216, 218, 223, 0.5)"; - ctx.fill(); } ctx.beginPath(); ctx.moveTo(425, -2775); ctx.arc(400, -2775, 25, 0, Math.PI); - ctx.fillStyle = "#c6aa12"; + ctx.fillStyle = lightOn ? "#ffe245" : "transparent"; ctx.fill(); ctx.strokeStyle = "#000000"; ctx.lineWidth = 1; @@ -18473,7 +18510,6 @@ const level = { if (!finishedGearFight && !pistonsLocked && m.pos.x > 2100 && m.pos.x < 2900 && m.pos.y > -1850 && m.pos.y < -1500) { pistonsLocked = true; - roofFallCycle = simulation.cycle + 250; roofReadyToFall = true; } @@ -18627,10 +18663,6 @@ const level = { distanceToIntersection = (circle3.radius * distance) / (circle3.radius + circle2.radius); slopeAngle = Math.atan((circle2.y - circle3.y) / (circle2.x - circle3.x)); angleToTangent = Math.acos(circle3.radius / distanceToIntersection); - const tangentPoint2 = { - x: Math.cos(angleToTangent + slopeAngle) * circle3.radius + circle3.x, - y: Math.sin(angleToTangent + slopeAngle) * circle3.radius + circle3.y - } const invertedTangentPoint2 = { x: Math.cos(-angleToTangent + slopeAngle) * circle3.radius + circle3.x, y: Math.sin(-angleToTangent + slopeAngle) * circle3.radius + circle3.y @@ -18640,10 +18672,6 @@ const level = { x: Math.cos(angleToTangent + slopeAngle) * -circle2.radius + circle2.x, y: Math.sin(angleToTangent + slopeAngle) * -circle2.radius + circle2.y } - const invertedTangentPoint3 = { - x: Math.cos(-angleToTangent + slopeAngle) * -circle2.radius + circle2.x, - y: Math.sin(-angleToTangent + slopeAngle) * -circle2.radius + circle2.y - } distance = Math.sqrt((piston2.position.y - 175 - circle3.y) ** 2 + (piston2.position.x - 50 - circle3.x) ** 2); slopeAngle = Math.atan((piston2.position.y - 175 - circle3.y) / (piston2.position.x - 50 - circle3.x)); @@ -18894,6 +18922,9 @@ const level = { var lastBlock = Math.sin(simulation.cycle / 50) < 0; level.customTopLayer = () => { + if (!lightOn) lightButton.query(); + if (!lightButton.isUp) lightOn = true; + lightButton.draw(); elevator1.move(); ctx.beginPath(); diff --git a/js/player.js b/js/player.js index f295e38..1643ce2 100644 --- a/js/player.js +++ b/js/player.js @@ -196,14 +196,11 @@ const m = { look() { }, //set to lookDefault() lookDefault() { //always on mouse look - m.angle = Math.atan2( - simulation.mouseInGame.y - m.pos.y, - simulation.mouseInGame.x - m.pos.x - ); + m.angle = Math.atan2(simulation.mouseInGame.y - m.pos.y, simulation.mouseInGame.x - m.pos.x); //smoothed mouse look translations const scale = 0.8; - m.transSmoothX = canvas.width2 - m.pos.x - (simulation.mouse.x - canvas.width2) * scale; - m.transSmoothY = canvas.height2 - m.pos.y - (simulation.mouse.y - canvas.height2) * scale; + m.transSmoothX = canvas.width2 - m.pos.x - (simulation.mouse.x - canvas.width2) * scale + m.transSmoothY = canvas.height2 - m.pos.y - (simulation.mouse.y - canvas.height2) * scale m.transX += (m.transSmoothX - m.transX) * m.lookSmoothing; m.transY += (m.transSmoothY - m.transY) * m.lookSmoothing; @@ -4609,6 +4606,7 @@ const m = { m.hole.isReady = false; m.fieldRange = 0 Matter.Body.setPosition(player, simulation.mouseInGame); + // simulation.translatePlayerAndCamera(simulation.mouseInGame) //too jerky m.buttonCD_jump = 0 //this might fix a bug with jumping const velocity = Vector.mult(Vector.normalise(sub), 20) Matter.Body.setVelocity(player, { diff --git a/js/powerup.js b/js/powerup.js index 8fef7cb..9f1e6dd 100644 --- a/js/powerup.js +++ b/js/powerup.js @@ -245,7 +245,7 @@ const powerUps = { dupExplode() { for (let i = 0, len = powerUp.length; i < len; ++i) { if (powerUp[i].isDuplicated) { - if (Math.random() < 0.003) { // (1-0.003)^240 = chance to be removed after 4 seconds, 240 = 4 seconds * 60 cycles per second + if (Math.random() < 0.003 && !m.isBodiesAsleep) { // (1-0.003)^240 = chance to be removed after 4 seconds, 240 = 4 seconds * 60 cycles per second b.explosion(powerUp[i].position, 175 + (11 + 3 * Math.random()) * powerUp[i].size); Matter.Composite.remove(engine.world, powerUp[i]); powerUp.splice(i, 1); @@ -1070,7 +1070,7 @@ const powerUps = { const choose = options[Math.floor(Math.seededRandom(0, options.length))] //pick an element from the array of options if (tech.isBanish) { tech.tech[choose].isBanished = true - if (i === 0) simulation.makeTextLog(`options.length = ${optionLengthNoDuplicates}`) + if (i === 0) simulation.makeTextLog(`options.length = ${optionLengthNoDuplicates} //tech removed from pool by decoherence`) } removeOption(choose) //move from future options pool to avoid repeats on this selection tech.tech[choose].isRecentlyShown = true //this flag prevents this option from being shown the next time you pick up a tech power up diff --git a/js/simulation.js b/js/simulation.js index a89422e..0a254ab 100644 --- a/js/simulation.js +++ b/js/simulation.js @@ -548,15 +548,31 @@ const simulation = { } } }, - noCameraScroll() { //makes the camera not scroll after changing locations - //only works if velocity is zero + translatePlayerAndCamera(where) { + //infinite falling. teleport to sky after falling + const before = { x: player.position.x, y: player.position.y, } + Matter.Body.setPosition(player, { x: where.x, y: where.y }); + const change = { x: before.x - player.position.x, y: before.y - player.position.y } + // translate camera to preserve illusion to endless fall + m.transX += change.x + m.transY += change.y + simulation.mouseInGame.x = (simulation.mouse.x - canvas.width2) / simulation.zoom * simulation.edgeZoomOutSmooth + canvas.width2 - m.transX; + simulation.mouseInGame.y = (simulation.mouse.y - canvas.height2) / simulation.zoom * simulation.edgeZoomOutSmooth + canvas.height2 - m.transY; + m.angle = Math.atan2(simulation.mouseInGame.y - m.pos.y, simulation.mouseInGame.x - m.pos.x); + + //is there a reason to update m.pos here? + // m.pos.x = player.position.x; + // m.pos.y = playerBody.position.y - m.yOff; + }, + setupCamera() { //makes the camera not scroll after changing locations + // //only works if velocity is zero m.pos.x = player.position.x; m.pos.y = playerBody.position.y - m.yOff; const scale = 0.8; m.transSmoothX = canvas.width2 - m.pos.x - (simulation.mouse.x - canvas.width2) * scale; m.transSmoothY = canvas.height2 - m.pos.y - (simulation.mouse.y - canvas.height2) * scale; - m.transX += (m.transSmoothX - m.transX) * 1; - m.transY += (m.transSmoothY - m.transY) * 1; + m.transX += (m.transSmoothX - m.transX); + m.transY += (m.transSmoothY - m.transY); }, edgeZoomOutSmooth: 1, camera() { @@ -570,6 +586,7 @@ const simulation = { ctx.translate(canvas.width2, canvas.height2); //center ctx.scale(simulation.zoom / simulation.edgeZoomOutSmooth, simulation.zoom / simulation.edgeZoomOutSmooth); //zoom in once centered ctx.translate(-canvas.width2 + m.transX, -canvas.height2 + m.transY); //translate + // ctx.translate(-canvas.width2 + m.transX - player.velocity.x, -canvas.height2 + m.transY + player.velocity.y); //translate //calculate in game mouse position by undoing the zoom and translations simulation.mouseInGame.x = (simulation.mouse.x - canvas.width2) / simulation.zoom * simulation.edgeZoomOutSmooth + canvas.width2 - m.transX; simulation.mouseInGame.y = (simulation.mouse.y - canvas.height2) / simulation.zoom * simulation.edgeZoomOutSmooth + canvas.height2 - m.transY; @@ -909,29 +926,51 @@ const simulation = { } if (m.pos.y > simulation.fallHeight) { // if 4000px deep - Matter.Body.setVelocity(player, { - x: 0, - y: 0 - }); - Matter.Body.setPosition(player, { - x: level.enter.x + 50, - y: level.enter.y - 20 - }); - // move bots - for (let i = 0; i < bullet.length; i++) { - if (bullet[i].botType) { - Matter.Body.setPosition(bullet[i], Vector.add(player.position, { - x: 250 * (Math.random() - 0.5), - y: 250 * (Math.random() - 0.5) - })); - Matter.Body.setVelocity(bullet[i], { - x: 0, - y: 0 - }); + if (level.isEndlessFall) { + //infinite falling. teleport to sky after falling + + simulation.ephemera.push({ + name: "slow player", + count: 130, //cycles before it self removes + do() { + this.count-- + if (this.count < 0 || m.onGround) simulation.removeEphemera(this.name) + // console.log(player.velocity.y) + if (player.velocity.y > 70) Matter.Body.setVelocity(player, { x: player.velocity.x * 0.99, y: player.velocity.y * 0.99 }); + if (player.velocity.y > 90) Matter.Body.setVelocity(player, { x: player.velocity.x * 0.99, y: player.velocity.y * 0.99 }); + }, + }) + + const before = { x: player.position.x, y: player.position.y, } + Matter.Body.setPosition(player, { x: level.enter.x, y: level.enter.y - 3000 }); + // Matter.Body.setPosition(player, level.fallPosition); + + const change = { x: before.x - player.position.x, y: before.y - player.position.y } + // translate camera smoothly to preserve illusion to endless fall + m.transX += change.x + m.transY += change.y + simulation.mouseInGame.x = (simulation.mouse.x - canvas.width2) / simulation.zoom * simulation.edgeZoomOutSmooth + canvas.width2 - m.transX; + simulation.mouseInGame.y = (simulation.mouse.y - canvas.height2) / simulation.zoom * simulation.edgeZoomOutSmooth + canvas.height2 - m.transY; + m.angle = Math.atan2(simulation.mouseInGame.y - m.pos.y, simulation.mouseInGame.x - m.pos.x); + + } else { + Matter.Body.setVelocity(player, { x: 0, y: 0 }); + Matter.Body.setPosition(player, { x: level.enter.x + 50, y: level.enter.y - 20 }); + m.damage(0.05 * simulation.difficultyMode); + m.energy -= 0.05 * simulation.difficultyMode + // move bots + for (let i = 0; i < bullet.length; i++) { + if (bullet[i].botType) { + Matter.Body.setPosition(bullet[i], Vector.add(player.position, { x: 250 * (Math.random() - 0.5), y: 250 * (Math.random() - 0.5) })); + Matter.Body.setVelocity(bullet[i], { x: 0, y: 0 }); + } } } - m.damage(0.1 * simulation.difficultyMode); - m.energy -= 0.1 * simulation.difficultyMode + + + + + } if (isNaN(player.position.x)) m.death(); if (m.lastKillCycle + 300 > m.cycle) { //effects active for 5 seconds after killing a mob @@ -959,6 +998,13 @@ const simulation = { } if (!(m.cycle % 420)) { //once every 7 seconds + //check if player is inside the map + if (Matter.Query.point(map, m.pos).length > 0 || Matter.Query.point(map, player.position).length > 0) { + // console.log('halp', Matter.Query.point(map, m.pos)) + Matter.Body.setVelocity(player, { x: 0, y: 0 }); + Matter.Body.setPosition(player, { x: level.enter.x + 50, y: level.enter.y - 20 }); + } + if (tech.isZeno) { if (tech.isEnergyHealth) { m.energy *= 0.95 @@ -975,10 +1021,7 @@ const simulation = { while (i--) { if (who[i].position.y > simulation.fallHeight) { if (save) { - Matter.Body.setVelocity(who[i], { - x: 0, - y: 0 - }); + Matter.Body.setVelocity(who[i], { x: 0, y: 0 }); Matter.Body.setPosition(who[i], { x: level.exit.x + 30 * (Math.random() - 0.5), y: level.exit.y + 30 * (Math.random() - 0.5) @@ -1016,6 +1059,7 @@ const simulation = { clearNow: false, clearMap() { level.isProcedural = false; + level.isEndlessFall = false; ctx.setTransform(1, 0, 0, 1, 0, 0); if (m.alive) { if (tech.isLongitudinal) b.guns[3].waves = []; //empty array of wave bullets diff --git a/js/spawn.js b/js/spawn.js index 01ef73c..fe8834b 100644 --- a/js/spawn.js +++ b/js/spawn.js @@ -1510,10 +1510,10 @@ const spawn = { // } // } me.do = function () { + this.checkStatus(); this.zombieHealthBar(); this.lookForMobTargets(); this.attack(); - this.checkStatus(); }; me.mobSearchIndex = 0; me.target = null @@ -1560,7 +1560,7 @@ const spawn = { } me.hitCD = 0 me.attack = function () { //hit non zombie mobs - if (this.hitCD < simulation.cycle) { + if (this.hitCD < simulation.cycle && !this.isStunned && !this.isSlowed) { if (this.target) { this.force = Vector.mult(Vector.normalise(Vector.sub(this.target.position, this.position)), this.accelMag * this.mass) } else { //wonder around diff --git a/js/tech.js b/js/tech.js index 2a32bcf..7e7cc17 100644 --- a/js/tech.js +++ b/js/tech.js @@ -3361,7 +3361,7 @@ const tech = { }, { name: "decoherence", - description: `tech options you don't choose won't reoccur
spawn ${powerUps.orb.research(6)}`, + description: `tech options you don't choose won't reoccur
spawn ${powerUps.orb.research(7)}`, maxCount: 1, count: 0, frequency: 1, @@ -3370,7 +3370,7 @@ const tech = { return !tech.isSuperDeterminism }, requires: "not superdeterminism", - bonusResearch: 6, + bonusResearch: 7, effect() { tech.isBanish = true for (let i = 0; i < this.bonusResearch; i++) powerUps.spawn(m.pos.x + 40 * (Math.random() - 0.5), m.pos.y + 40 * (Math.random() - 0.5), "research", false); @@ -5662,19 +5662,19 @@ const tech = { }, { name: "shaped charge", - description: `use ${powerUps.orb.research(3)} to dynamically reduce
all explosions to prevent health loss`, + description: `use ${powerUps.orb.research(2)} to dynamically reduce
all explosions to prevent health loss`, isGunTech: true, maxCount: 1, count: 0, frequency: 2, frequencyDefault: 2, allowed() { - return !tech.isImmuneExplosion && (build.isExperimentSelection || powerUps.research.count > 2) && (tech.haveGunCheck("missiles") || (m.fieldMode === 4 && simulation.molecularMode === 1) || tech.missileBotCount > 0 || tech.isIncendiary || tech.isPulseLaser || tech.isTokamak || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb)) + return !tech.isImmuneExplosion && (build.isExperimentSelection || powerUps.research.count > 1) && (tech.haveGunCheck("missiles") || (m.fieldMode === 4 && simulation.molecularMode === 1) || tech.missileBotCount > 0 || tech.isIncendiary || tech.isPulseLaser || tech.isTokamak || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb)) }, requires: "an explosive damage source, not rocket propelled grenade", effect() { tech.isSmartRadius = true; - for (let i = 0; i < 3; i++) { + for (let i = 0; i < 2; i++) { if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1) } }, @@ -5731,9 +5731,9 @@ const tech = { frequency: 2, frequencyDefault: 2, allowed() { - return tech.haveGunCheck("grenades") && !tech.isVacuumBomb + return tech.haveGunCheck("grenades") && !tech.isVacuumBomb && !tech.isSmartRadius }, - requires: "grenades, not vacuum bomb", + requires: "grenades, not vacuum bomb, shaped charges", effect() { tech.isImmuneExplosion = true; tech.isRPG = true; @@ -6615,12 +6615,12 @@ const tech = { isGunTech: true, maxCount: 1, count: 0, - frequency: 2, - frequencyDefault: 2, + frequency: 1, + frequencyDefault: 1, allowed() { - return !tech.isBulletTeleport && (tech.haveGunCheck("foam") || tech.isFoamBotUpgrade || tech.isFoamShot || tech.isFoamBall || tech.isFoamMine) + return tech.haveGunCheck("foam") || tech.isFoamBotUpgrade || tech.isFoamShot || tech.isFoamBall || tech.isFoamMine }, - requires: "foam, not uncertainty", + requires: "foam", effect() { tech.isFoamAttract = true }, @@ -6637,9 +6637,9 @@ const tech = { frequency: 1, frequencyDefault: 1, allowed() { - return (!tech.isFoamAttract && (tech.haveGunCheck("foam") || tech.isFoamBotUpgrade || tech.isFoamShot || tech.isFoamBall || tech.isFoamMine)) || (tech.haveGunCheck("wave") && !tech.is360Longitudinal) || (tech.haveGunCheck("super balls") && !tech.isSuperHarm) || tech.isSoundBotUpgrade + return (tech.haveGunCheck("foam") || tech.isFoamBotUpgrade || tech.isFoamShot || tech.isFoamBall || tech.isFoamMine) || (tech.haveGunCheck("wave") && !tech.is360Longitudinal) || (tech.haveGunCheck("super balls") && !tech.isSuperHarm) || tech.isSoundBotUpgrade }, - requires: "foam, wave, super balls, not isotropic, electrostatic induction, Zectron", + requires: "foam, wave, super balls, not isotropic, Zectron", effect() { tech.isBulletTeleport = true }, @@ -7179,7 +7179,7 @@ const tech = { }, { name: "compound lens", - description: "+50% laser lens damage
+15° lens arc", + description: "+40% laser lens damage
+25° lens arc", isGunTech: true, maxCount: 9, count: 0, @@ -7190,8 +7190,8 @@ const tech = { }, requires: "lens", effect() { - b.guns[11].arcRange += 15 * Math.PI / 180 / 2 - b.guns[11].lensDamageOn += 0.5 + b.guns[11].arcRange += 25 * Math.PI / 180 / 2 + b.guns[11].lensDamageOn += 0.4 }, remove() { b.guns[11].arcRange = 90 * Math.PI / 180 / 2 //0.78 divded by 2 because of how it's drawn diff --git a/todo.txt b/todo.txt index 010889f..246090e 100644 --- a/todo.txt +++ b/todo.txt @@ -1,14 +1,21 @@ ******************************************************** NEXT PATCH ************************************************** -new mob type: hopMother - hoppers that drop eggs that explode on contact and after several seconds they hatch into baby hoppers - regular hopper mobs have more life and more damage +after falling off most open maps you don't take damage + you fall down into the level again above the entrance -a few bug fixes +disabled smooth camera tracking for + portals + falling off map + +added a once every 7 seconds check to see if the player is suck inside the map + if stuck you teleport to the level entrance + catches about 90% of the ways to get stuck from falling too fast + this might causing problems after more testing, not sure + +bug fixes *********************************************************** TODO ***************************************************** -a mob/boss? that drops the mines from reactor and final boss - more (all) bosses need to be made of parts good examples: spiderBoss, dragonFlyBoss, beetleBoss methods: @@ -1108,7 +1115,7 @@ possible names for tech magnetorquers - produce spin by pushing on earth's magnetic field Josephson junction - superconducting junction Pyroelectricity - voltage from temp changes - upgrade from piezoelectricity - dark star - upgrade to WIMPs + perturbation ******************************************************** CARS IMAGES ********************************************************