diff --git a/js/bullet.js b/js/bullet.js index a117aae..76c2df8 100644 --- a/js/bullet.js +++ b/js/bullet.js @@ -2832,19 +2832,13 @@ const b = { } if (tech.isLaserPush) { //push mobs away const index = path.length - 1 - Matter.Body.setVelocity(best.who, { - x: best.who.velocity.x * 0.97, - y: best.who.velocity.y * 0.97 - }); + Matter.Body.setVelocity(best.who, { x: best.who.velocity.x * 0.97, y: best.who.velocity.y * 0.97 }); const force = Vector.mult(Vector.normalise(Vector.sub(path[index], path[Math.max(0, index - 1)])), 0.003 * push * Math.min(6, best.who.mass)) Matter.Body.applyForce(best.who, path[index], force) } } else if (tech.isLaserPush && best.who.classType === "body") { const index = path.length - 1 - Matter.Body.setVelocity(best.who, { - x: best.who.velocity.x * 0.97, - y: best.who.velocity.y * 0.97 - }); + Matter.Body.setVelocity(best.who, { x: best.who.velocity.x * 0.97, y: best.who.velocity.y * 0.97 }); const force = Vector.mult(Vector.normalise(Vector.sub(path[index], path[Math.max(0, index - 1)])), 0.003 * push * Math.min(6, best.who.mass)) Matter.Body.applyForce(best.who, path[index], force) } @@ -3679,7 +3673,7 @@ const b = { }, speed = 1) { const me = bullet.length; const THRUST = 0.0015 - const dir = m.angle + 0.4 * (Math.random() - 0.5); + const dir = m.angle + 0.2 * (Math.random() - 0.5); const RADIUS = (4.5 + 3 * Math.random()) bullet[me] = Bodies.polygon(where.x, where.y, 8, RADIUS, { angle: dir, @@ -3822,7 +3816,7 @@ const b = { !mob[i].isInvulnerable ) { const TARGET_VECTOR = Vector.sub(this.position, mob[i].position) - const DIST = Vector.magnitude(TARGET_VECTOR); + const DIST = Vector.magnitude(TARGET_VECTOR) if (DIST < closeDist) { closeDist = DIST; this.lockedOn = mob[i] @@ -3931,18 +3925,12 @@ const b = { } // speed cap instead of friction to give more agility if (this.speed > 6) { - Matter.Body.setVelocity(this, { - x: this.velocity.x * 0.97, - y: this.velocity.y * 0.97 - }); + Matter.Body.setVelocity(this, { x: this.velocity.x * 0.97, y: this.velocity.y * 0.97 }); } } }) Composite.add(engine.world, bullet[me]); //add bullet to world - Matter.Body.setVelocity(bullet[me], { - x: speed * Math.cos(dir), - y: speed * Math.sin(dir) - }); + Matter.Body.setVelocity(bullet[me], { x: speed * Math.cos(dir), y: speed * Math.sin(dir) }); }, droneRadioactive(where = { x: m.pos.x + 30 * Math.cos(m.angle) + 20 * (Math.random() - 0.5), @@ -7732,7 +7720,7 @@ const b = { x: m.pos.x + 30 * Math.cos(m.angle) + 10 * (Math.random() - 0.5), y: m.pos.y + 30 * Math.sin(m.angle) + 10 * (Math.random() - 0.5) }, 45) - m.fireCDcycle = m.cycle + Math.floor(50 * b.fireCDscale); // cool down + m.fireCDcycle = m.cycle + Math.floor(45 * b.fireCDscale); // cool down } else { b.droneRadioactive({ x: m.pos.x + 30 * Math.cos(m.angle) + 10 * (Math.random() - 0.5), @@ -7743,16 +7731,16 @@ const b = { } else { if (m.crouch) { b.drone({ - x: m.pos.x + 30 * Math.cos(m.angle) + 10 * (Math.random() - 0.5), - y: m.pos.y + 30 * Math.sin(m.angle) + 10 * (Math.random() - 0.5) - }, 55) - m.fireCDcycle = m.cycle + Math.floor(10 * b.fireCDscale); // cool down + x: m.pos.x + 30 * Math.cos(m.angle) + 5 * (Math.random() - 0.5), + y: m.pos.y + 30 * Math.sin(m.angle) + 5 * (Math.random() - 0.5) + }, 50) + m.fireCDcycle = m.cycle + Math.floor(7 * b.fireCDscale); // cool down } else { b.drone({ x: m.pos.x + 30 * Math.cos(m.angle) + 10 * (Math.random() - 0.5), y: m.pos.y + 30 * Math.sin(m.angle) + 10 * (Math.random() - 0.5) - }, 20) - m.fireCDcycle = m.cycle + Math.floor(5 * b.fireCDscale); // cool down + }, 15) + m.fireCDcycle = m.cycle + Math.floor(4 * b.fireCDscale); // cool down } } } @@ -7788,14 +7776,8 @@ const b = { const radius = 5 + 8 * Math.random() + (tech.isAmmoFoamSize && this.ammo < 300) * 12 const SPEED = (m.crouch ? 1.2 : 1) * Math.max(2, 14 - radius * 0.25) const dir = m.angle + 0.15 * (Math.random() - 0.5) - const velocity = { - x: SPEED * Math.cos(dir), - y: SPEED * Math.sin(dir) - } - const position = { - x: m.pos.x + 30 * Math.cos(m.angle), - y: m.pos.y + 30 * Math.sin(m.angle) - } + const velocity = { x: SPEED * Math.cos(dir), y: SPEED * Math.sin(dir) } + const position = { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) } b.foam(position, Vector.rotate(velocity, spread), radius) this.applyKnock(velocity) m.fireCDcycle = m.cycle + Math.floor(1.5 * b.fireCDscale); diff --git a/js/level.js b/js/level.js index 62d16ad..fdd10eb 100644 --- a/js/level.js +++ b/js/level.js @@ -11,14 +11,14 @@ const level = { //see level.populateLevels: (intro, ... , reservoir or factory, reactor, ... , gauntlet, final) added later playableLevels: ["labs", "rooftops", "skyscrapers", "warehouse", "highrise", "office", "aerie", "satellite", "sewers", "testChamber", "pavilion", "lock"], communityLevels: ["gauntlet", "stronghold", "basement", "crossfire", "vats", "run", "ngon", "house", "perplex", "coliseum", "tunnel", "islands", "temple", "dripp", "biohazard", "stereoMadness", "yingYang", "staircase", "fortress", "commandeer", "clock", "buttonbutton", "downpour", "superNgonBros", "underpass", "cantilever", "dojo", "tlinat", "ruins"], - trainingLevels: ["walk", "crouch", "jump", "hold", "throw", "throwAt", "deflect", "heal", "fire", "nailGun", "shotGun", "superBall", "matterWave", "missile", "stack", "mine", "grenades", "harpoon"], + trainingLevels: ["walk", "crouch", "jump", "hold", "throw", "throwAt", "deflect", "heal", "fire", "nailGun", "shotGun", "superBall", "matterWave", "missile", "stack", "mine", "grenades", "harpoon", "diamagnetism"], 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.isHorizontalFlipped = true // tech.giveTech("performance") - // level.difficultyIncrease(2 * 4) //30 is near max on hard //60 is near max on why + // level.difficultyIncrease(1 * 4) //30 is near max on hard //60 is near max on why // spawn.setSpawnList(); // spawn.setSpawnList(); // m.maxHealth = m.health = 100 @@ -27,7 +27,7 @@ const level = { // 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("time dilation") //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); @@ -35,8 +35,6 @@ const level = { // 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 // tech.giveTech("von Neumann probe") - // tech.giveTech("path integration") - // tech.giveTech("cordyceps") // for (let i = 0; i < 1; ++i) tech.giveTech("mass production") // for (let i = 0; i < 2; ++i) tech.giveTech("sound-bot") // for (let i = 0; i < 1; ++i) tech.giveTech("foam-bot") @@ -50,10 +48,12 @@ const level = { // for (let i = 0; i < 3; i++) powerUps.directSpawn(450, -50, "tech"); // 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(); - // for (let i = 0; i < 2; ++i) spawn.starter(1900, -500, 50) - // spawn.sneaker(1900, -500, 25) - // spawn.sniper(2000, -450) + level.diamagnetism(); + // for (let i = 0; i < 1; ++i) spawn.slasher(1900, -500) + // for (let i = 0; i < 1; ++i) spawn.slasher2(1900, -500) + // for (let i = 0; i < 1; ++i) spawn.shooterBoss(1900, -2500) + // spawn.suckerBoss(1900, -500, 25) + // spawn.slasher2(2000, -1150) // spawn.zombie(-3000, -500 + 300 * Math.random(), 30, 5, "white") // zombie(x, y, radius, sides, color) // for (let i = 0; i < 20; ++i) spawn.starter(1000 + 1000 * Math.random(), -500 + 300 * Math.random()) // tech.addJunkTechToPool(2) @@ -61,14 +61,14 @@ 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; // simulation.setZoom(); // for (let i = 0; i < 2; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "tech"); // for (let i = 0; i < 2; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "boost"); - // for (let i = 0; i < 100; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "heal"); + // for (let i = 0; i < 2; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "heal"); // for (let i = 0; i < 2; i++) powerUps.spawn(player.position.x + Math.random() * 50, player.position.y - Math.random() * 50, "field", false); //lore testing // for (let i = 0; i < 5; i++) tech.giveTech("undefined") @@ -1994,10 +1994,10 @@ const level = { //??? - level.difficultyIncrease(3 * 4) //30 is near max on hard //60 is near max on why + // level.difficultyIncrease(3 * 4) //30 is near max on hard //60 is near max on why // m.addHealth(Infinity) - spawn.starter(1900, -500, 200) //big boy + // spawn.starter(1900, -500, 200) //big boy // spawn.starter(1900, -500, 100) //big boy // for (let i = 0; i < 10; ++i) spawn.launcher(1900, -500) // spawn.suckerBoss(1900, -500) @@ -26050,364 +26050,225 @@ const level = { }, tlinat() { // _Destined_ formerly Richard0820#2652 simulation.makeTextLog(`tlinat by Richard0820`); - - simulation.fallHeight = Infinity; - level.setPosToSpawn(0, -1000); - level.exit.x = 5100; - level.exit.y = 3770; - spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); - spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20); - level.defaultZoom = 2500 - simulation.zoomTransition(level.defaultZoom) - document.body.style.backgroundColor = "#d8dadf"; - let teleportIndex = 0; - let footIndex = 0; - simulation.makeTextLog(`Walk right to tp to maze
Exit is at the bottom left`) - Matter.Body.scale(player.parts[3], 2, 2); - level.custom = () => { - level.exit.drawAndCheck(); - level.enter.draw(); - if (player.position.y > 100000) { + simulation.fallHeight = 1 / 0, level.setPosToSpawn(0, -1e3), level.exit.x = 5100, level.exit.y = 3770, spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20), spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20), level.defaultZoom = 3000, simulation.zoomTransition(level.defaultZoom), document.body.style.backgroundColor = "#d8dadf"; + let e = 0, + t = 0; + const boidsFlocking = function (mob, otherMobs) { + const cohesionFactor = 0.01; + const separationFactor = 0.0001; + const alignmentFactor = 0.04; + let averagePosition = { x: 0, y: 0 }; + let averageVelocity = { x: 0, y: 0 }; + let nearbyMobsCount = 0; + for (const otherMob of otherMobs) { + if (otherMob !== mob) { + const distanceSquared = Vector.magnitudeSquared(Vector.sub(mob.position, otherMob.position)); + const boidRangeSquared = 300 * 300; // Adjust boid range as needed + if (distanceSquared < boidRangeSquared) { + averagePosition = Vector.add(averagePosition, otherMob.position); + averageVelocity = Vector.add(averageVelocity, otherMob.velocity); + nearbyMobsCount++; + } + } + } + if (nearbyMobsCount > 0) { + averagePosition = Vector.div(averagePosition, nearbyMobsCount); + averageVelocity = Vector.div(averageVelocity, nearbyMobsCount); + const cohesionForce = Vector.mult(Vector.sub(averagePosition, mob.position), cohesionFactor); + mob.force = Vector.add(mob.force, cohesionForce); + const separationForce = Vector.mult(Vector.sub(mob.position, averagePosition), separationFactor); + mob.force = Vector.add(mob.force, separationForce); + const alignmentForce = Vector.mult(Vector.sub(averageVelocity, mob.velocity), alignmentFactor); + mob.force = Vector.add(mob.force, alignmentForce); + } + }; + function ghoster(x, y, radius = 50 + Math.ceil(Math.random() * 90)) { + mobs.spawn(x, y, 7, radius, "transparent"); + let me = mob[mob.length - 1]; + me.seeAtDistance2 = 300000; + me.accelMag = 0.00004 + 0.00015 * simulation.accelScale; + if (map.length) me.searchTarget = map[Math.floor(Math.random() * (map.length - 1))].position; //required for search + // Matter.Body.setDensity(me, 0.0015); //normal is 0.001 + me.damageReduction = 0.5 + me.stroke = "transparent"; //used for drawGhost + me.alpha = 1; //used in drawGhost + me.isNotCloaked = false; //used in drawGhost + me.isBadTarget = true; + // me.leaveBody = false; + me.collisionFilter.mask = cat.bullet //| cat.body + me.showHealthBar = false; + me.memory = 600; + me.do = function () { + boidsFlocking(me, mob);//Stack, increase power. + if (this.speed > 7) { + Matter.Body.setVelocity(this, { + x: this.velocity.x * 0.8, + y: this.velocity.y * 0.8 + }); + } + this.seePlayerCheckByDistance(); + this.checkStatus(); + this.attraction(); + this.search(); + //draw + if (this.distanceToPlayer2() < this.seeAtDistance2) { + if (this.alpha < 1) this.alpha += 0.011 * simulation.CDScale; //near player go solid + } else { + if (this.alpha > 0) this.alpha -= 0.05; ///away from player, hide + } + if (this.alpha > 0) { + if (this.alpha > 0.7 && this.seePlayer.recall) { + this.healthBar(); + if (!this.isNotCloaked) { + this.isNotCloaked = true; + this.isBadTarget = false; + this.collisionFilter.mask = cat.player | cat.bullet + } + } + //draw body + ctx.beginPath(); + const vertices = this.vertices; + ctx.moveTo(vertices[0].x, vertices[0].y); + for (let j = 1, len = vertices.length; j < len; ++j) { + ctx.lineTo(vertices[j].x, vertices[j].y); + } + ctx.lineTo(vertices[0].x, vertices[0].y); + // ctx.lineWidth = 1; + ctx.fillStyle = `rgba(255,255,255,${this.alpha * this.alpha})`; + ctx.fill(); + } else if (this.isNotCloaked) { + this.isNotCloaked = false; + this.isBadTarget = true; + this.collisionFilter.mask = cat.bullet; //can't touch player or walls + } + }; + } + function o(e, t, o) { + const l = { + J: [" #### ", " # ", " # ", " # ", " # # ", " # # ", " ## "], + I: [" # ", " # ", " # ", " # ", " # ", " # ", " # "], + N: [" # # ", " ## # ", " ## # ", " # ## ", " # ## ", " # # ", " # # "], + " ": [" ", " ", " ", " ", " ", " ", " "], + O: [" ## ", " # # ", " # # ", " # # ", " # # ", " # # ", " ## "], + U: [" # # ", " # # ", " # # ", " # # ", " # # ", " # # ", " ### "], + R: [" #### ", " # #", " #### ", " # # ", " # # ", " # #", " # #"], + D: [" ### ", " # ## ", " # # ", " # # ", " # # ", " # ## ", " ### "], + S: [" #### ", " # ", " # ", " ### ", " ## ", " # ", " ##### "], + C: [" ##### ", " # ", " # ", " # ", " # ", " # ", " ##### "], + V: [" # # ", " # # ", " # # ", " # # ", " # # ", " # # ", " # "], + E: [" ##### ", " # ", " # ", " ##### ", " # ", " # ", " ##### "], + ".": [" ", " ", " ", " ", " ", " ## ", " ## "], + "/": [" #", " # ", " # ", " # ", " # ", " # ", "# "], + G: [" ###### ", " # ", " # ", " # ### ", " # # ", " # # ", " ###### "], + Q: [" ###### ", " # # ", " # # ", " # # ", " # # # ", " # # ", " #### # ", " # "], + 8: [" ##### ", " # # ", " # # ", " ##### ", " # # ", " # # ", " ##### "], + g: [" ##### ", " # # ", " # # ", " ##### ", " # ", " # ", " ###### "], + Y: [" # # ", " # # ", " # # ", " # ", " # ", " # ", " # "], + 4: [" # ", " # # ", " # # ", " # # ", " ###### ", " # ", " # "], + W: [" # # ", " # # ", " # # ", " # # # ", " # # # # ", " ## ## ", " # # "], + e: [" ###### ", " # # ", " # # ", " ####### ", " # ", " # ", " ###### "], + c: [" ###### ", "# ", "# ", "# ", "# ", "# ", " ###### ", " "], + m: [" # ", " ### ### ", " # # # ", " # # # ", " # # # ", " # # # ", " # # # "] + }, + a = (e, t) => { + ctx.fillStyle = "black", ctx.fillRect(e, t, 50, 50) + }, + n = (e, t, o) => { + const n = l[e]; + if (n) + for (let e = 0; e < n.length; e++) { + const l = n[e]; + for (let n = 0; n < l.length; n++) { + if ("#" === l[n]) { + a(t + 20 * n, o + 20 * e) + } + } + } + }; + for (let l = 0; l < o.length; l++) { + n(o[l], e + 250 * l - Math.abs(1.5 * e), t) + } + } + simulation.makeTextLog(`
Look up
Walk right to tp to maze
Exit is at the bottom left`), Matter.Body.scale(player.parts[3], 2, 2), level.custom = () => { + if (level.exit.drawAndCheck(), level.enter.draw(), player.position.y > 1e5 && Matter.Body.setPosition(player, { + x: 5100, + y: -5925 + }), player.position.x > 2500 && 0 == e) { Matter.Body.setPosition(player, { x: 5100, y: -5925 - }) + }), e++; + for (let e = 0; e < map.length; e++) Math.random() < .75 && ghoster(map[e].position.x, map[e].position.y); + simulation.makeTextLog("Watch out for ghosters
Peace ✌️") } - if (player.position.x > 2500 && teleportIndex == 0) { - Matter.Body.setPosition(player, { - x: 5100, - y: -5925 - }) - teleportIndex++; - for (let i = 0; i < map.length; i++) { - if (Math.random() < 0.75) { //75% chance - spawn.ghoster(map[i].position.x, map[i].position.y) + player.position.x > level.exit.x && player.position.x < level.exit.x + 100 && player.position.y > level.exit.y - 150 && player.position.y < level.exit.y - 0 && player.velocity.y < .15 && 0 == t && (t++, Matter.Body.scale(player.parts[3], .5, .5)) + }, level.customTopLayer = () => { + player.position.x > -1200 && player.position.x < 4500 && (o(2e3, -3e3, "JOIN OUR DISCORD SERVER"), o(1500, -2700, "DISCORD.GG/Q8gY4WeUcm")) + }, spawn.mapRect(-1e3, -950, 5950, 100), spawn.mapRect(-1325, -3450, 100, 2575), spawn.mapRect(-1325, -950, 350, 100), spawn.mapRect(4850, -3400, 100, 2550), spawn.mapRect(-1325, -3450, 6275, 100), + function (e, t, o, l, a) { + const n = o / a, + s = l / a, + i = e - o / 2, + p = t - l / 2, + r = []; + for (let e = 0; e < a; e++) { + r[e] = []; + for (let t = 0; t < a; t++) r[e][t] = 1 + } + const c = []; + (function e(t, o) { + r[t][o] = 0; + const l = [{ + dx: 0, + dy: -1 + }, { + dx: 1, + dy: 0 + }, { + dx: 0, + dy: 1 + }, { + dx: -1, + dy: 0 + }]; + l.sort((() => Math.random() - .5)); + for (const n of l) { + const l = t + 2 * n.dx, + s = o + 2 * n.dy; + l >= 0 && l < a && s >= 0 && s < a && 1 === r[l][s] && (r[t + n.dx][o + n.dy] = 0, r[l][s] = 0, c.push({ + x: t + n.dx, + y: o + n.dy + }), e(l, s)) } - } - simulation.makeTextLog(`Watch out for ghosters
Peace ✌️`) - } - if ( //check - player.position.x > level.exit.x && - player.position.x < level.exit.x + 100 && - player.position.y > level.exit.y - 150 && - player.position.y < level.exit.y - 0 && - player.velocity.y < 0.15 && - footIndex == 0 - ) { - footIndex++; - Matter.Body.scale(player.parts[3], 1 / 2, 1 / 2); - } - //ctx.drawImage(image, 1650 - 750, -2450, 725, 725) - }; - level.customTopLayer = () => { - if (player.position.x > -1200 && player.position.x < 4500) { //does not render when in the maze - drawText(2000, -3000, "JOIN OUR DISCORD SERVER"); - ctx.fillStyle = "black" - ctx.fillRect(1725, -2375, 25, 175); - ctx.fillRect(1725, -2375, 175, 25); - ctx.fillRect(1875, -2375, 25, 175); - ctx.fillRect(1725, -2225, 175, 25); - ctx.fillRect(1800, -2325, 25, 25); - ctx.fillRect(1775, -2325, 75, 75); - ctx.fillRect(1925, -2350, 50, 25); - ctx.fillRect(1950, -2350, 25, 25); - ctx.fillRect(1950, -2375, 25, 100); - ctx.fillRect(1925, -2300, 50, 25); - ctx.fillRect(1925, -2250, 25, 50); - ctx.fillRect(1975, -2275, 25, 75); - ctx.fillRect(1975, -2325, 50, 25); - ctx.fillRect(2000, -2350, 25, 75); - ctx.fillRect(2000, -2350, 100, 25); - ctx.fillRect(2075, -2375, 25, 50); - ctx.fillRect(2125, -2375, 25, 25); - ctx.fillRect(2175, -2375, 25, 175); - ctx.fillRect(2175, -2225, 175, 25); - ctx.fillRect(2325, -2375, 25, 175); - ctx.fillRect(2175, -2375, 175, 25); - ctx.fillRect(2225, -2300, 25, 25); - ctx.fillRect(2225, -2325, 75, 75); - ctx.fillRect(2025, -2275, 25, 25); - ctx.fillRect(2050, -2300, 25, 25); - ctx.fillRect(2100, -2300, 50, 50); - ctx.fillRect(2050, -2250, 75, 25); - ctx.fillRect(2075, -2250, 25, 50); - ctx.fillRect(1725, -2175, 125, 25); - ctx.fillRect(1800, -2175, 50, 50); - ctx.fillRect(1875, -2175, 100, 25); - ctx.fillRect(1725, -2125, 25, 175); - ctx.fillRect(1725, -2125, 50, 25); - ctx.fillRect(1725, -2075, 75, 50); - ctx.fillRect(1775, -2100, 25, 75); - ctx.fillRect(1775, -2075, 50, 25); - ctx.fillRect(1825, -2050, 25, 50); - ctx.fillRect(1800, -2025, 50, 25); - ctx.fillRect(1775, -2000, 25, 25); - ctx.fillRect(1800, -1975, 25, 25); - ctx.fillRect(1975, -2175, 25, 25); - ctx.fillRect(1900, -2175, 25, 150); - ctx.fillRect(1875, -2025, 25, 25); - ctx.fillRect(1925, -2025, 25, 25); - ctx.fillRect(1900, -2000, 25, 25); - ctx.fillRect(1875, -1975, 25, 25); - ctx.fillRect(1950, -2000, 25, 25); - ctx.fillRect(1925, -1975, 75, 50); - ctx.fillRect(1925, -1925, 25, 25); - ctx.fillRect(2025, -2225, 25, 75); - ctx.fillRect(2125, -2225, 25, 50); - ctx.fillRect(1875, -2125, 50, 25); - ctx.fillRect(1850, -2075, 125, 25); - ctx.fillRect(1950, -2175, 25, 125); - ctx.fillRect(1950, -2100, 75, 25); - ctx.fillRect(2000, -2125, 25, 75); - ctx.fillRect(1975, -2050, 25, 25); - ctx.fillRect(2025, -2050, 25, 25); - ctx.fillRect(2000, -2125, 75, 25); - ctx.fillRect(2050, -2125, 25, 50); - ctx.fillRect(2050, -2100, 50, 25); - ctx.fillRect(2075, -2175, 50, 50); - ctx.fillRect(2100, -2150, 25, 50); - ctx.fillRect(2100, -2075, 25, 25); - ctx.fillRect(2125, -2100, 50, 25); - ctx.fillRect(2150, -2175, 25, 100); - ctx.fillRect(2100, -2150, 75, 25); - ctx.fillRect(1725, -1925, 25, 175); - ctx.fillRect(1725, -1925, 175, 25); - ctx.fillRect(1875, -1925, 25, 175); - ctx.fillRect(1725, -1775, 175, 25); - ctx.fillRect(1775, -1875, 75, 75); - ctx.fillRect(1925, -1875, 25, 125); - ctx.fillRect(1925, -1775, 75, 25); - ctx.fillRect(1925, -1875, 125, 25); - ctx.fillRect(2025, -1875, 25, 100); - ctx.fillRect(1975, -1900, 25, 75); - ctx.fillRect(1975, -1900, 50, 25); - ctx.fillRect(2000, -1925, 100, 25); - ctx.fillRect(2050, -2025, 50, 25); - ctx.fillRect(2050, -2025, 25, 50); - ctx.fillRect(2025, -2000, 50, 25); - ctx.fillRect(2025, -2000, 25, 50); - ctx.fillRect(2025, -1825, 75, 25); - ctx.fillRect(2075, -1825, 25, 50); - ctx.fillRect(2100, -1775, 25, 25); - ctx.fillRect(2075, -1875, 25, 25); - ctx.fillRect(2100, -1850, 50, 25); - ctx.fillRect(2125, -1975, 25, 150); - ctx.fillRect(2150, -2125, 50, 25); - ctx.fillRect(2200, -2175, 25, 50); - ctx.fillRect(2200, -2150, 50, 25); - ctx.fillRect(2225, -2150, 25, 50); - ctx.fillRect(2250, -2175, 25, 25); - ctx.fillRect(2300, -2175, 25, 25); - ctx.fillRect(2325, -2150, 25, 25); - ctx.fillRect(2275, -2125, 25, 25); - ctx.fillRect(2175, -2075, 100, 25); - ctx.fillRect(2300, -2075, 50, 25); - ctx.fillRect(2125, -2050, 125, 25); - ctx.fillRect(2225, -2075, 25, 75); - ctx.fillRect(2175, -2050, 25, 50); - ctx.fillRect(2150, -2050, 25, 75); - ctx.fillRect(2075, -1975, 200, 25); - ctx.fillRect(2225, -1975, 25, 200); - ctx.fillRect(2175, -1925, 25, 25); - ctx.fillRect(2125, -1875, 150, 25); - ctx.fillRect(2250, -1900, 25, 50); - ctx.fillRect(2275, -1925, 75, 25); - ctx.fillRect(2325, -2025, 25, 125); - ctx.fillRect(2275, -2025, 75, 25); - ctx.fillRect(2300, -2025, 50, 50); - ctx.fillRect(2175, -1875, 25, 50); - ctx.fillRect(2125, -1800, 150, 25); - ctx.fillRect(2275, -1825, 25, 25); - ctx.fillRect(2300, -1850, 50, 25); - ctx.fillRect(2325, -1850, 25, 50); - ctx.fillRect(2300, -1800, 25, 50); - ctx.fillRect(2275, -1775, 75, 25); - } - }; - spawn.mapRect(-1000, -950, 5950, 100); - spawn.mapRect(-1325, -3450, 100, 2575); - spawn.mapRect(-1325, -950, 350, 100); - spawn.mapRect(4850, -3400, 100, 2550); - spawn.mapRect(-1325, -3450, 6275, 100); - maze(10000, -1000, 10000, 10000, 50); - - function maze(x, y, width, height, cells) { - const cellWidth = width / cells; - const cellHeight = height / cells; - const startX = x - (width / 2); - const startY = y - (height / 2); - const matrix = []; - for (let i = 0; i < cells; i++) { - matrix[i] = []; - for (let j = 0; j < cells; j++) { - matrix[i][j] = 1; - } - } - const stack = []; - - function carveMaze(x, y) { - matrix[x][y] = 0; - const directions = [{ - dx: 0, - dy: -1 - }, // Up - { - dx: 1, - dy: 0 - }, // Right - { - dx: 0, - dy: 1 - }, // Down - { - dx: -1, - dy: 0 - } // Left - ]; - directions.sort(() => Math.random() - 0.5); - for (const direction of directions) { - const nextX = x + direction.dx * 2; - const nextY = y + direction.dy * 2; - if (nextX >= 0 && nextX < cells && nextY >= 0 && nextY < cells && matrix[nextX][nextY] === 1) { - matrix[x + direction.dx][y + direction.dy] = 0; - matrix[nextX][nextY] = 0; - stack.push({ - x: x + direction.dx, - y: y + direction.dy - }); - carveMaze(nextX, nextY); - } - } - } - carveMaze(0, 0); - matrix[cells - 1][cells - 1] = 1; - for (let i = -1; i < cells + 1; i++) { - let startCol = -1; - let endCol = -1; - for (let j = -1; j < cells + 1; j++) { - if (i >= 0 && i < cells && j >= 0 && j < cells && matrix[i][j] === 1) { - if (startCol === -1) { - startCol = j; + })(0, 0), r[a - 1][a - 1] = 1; + for (let e = -1; e < a + 1; e++) { + let t = -1, + o = -1; + for (let l = -1; l < a + 1; l++) + if (e >= 0 && e < a && l >= 0 && l < a && 1 === r[e][l]) - 1 === t && (t = l), o = l; + else if (-1 !== t) { + const l = i + e * n, + a = p + t * s, + r = n, + c = (o - t + 1) * s; + c !== s && spawn.mapRect(l, a, r, c), t = -1, o = -1 } - endCol = j; - } else { - if (startCol !== -1) { - const rectX = startX + i * cellWidth; - const rectY = startY + startCol * cellHeight; - const rectWidth = cellWidth; - const rectHeight = (endCol - startCol + 1) * cellHeight; - if (rectHeight !== cellHeight) { - spawn.mapRect(rectX, rectY, rectWidth, rectHeight); - } - startCol = -1; - endCol = -1; - } - } } - } - for (let j = -1; j < cells + 1; j++) { - let startRow = -1; - let endRow = -1; - for (let i = -1; i < cells + 1; i++) { - if (i >= 0 && i < cells && j >= 0 && j < cells && matrix[i][j] === 1) { - if (startRow === -1) { - startRow = i; + for (let e = -1; e < a + 1; e++) { + let t = -1, + o = -1; + for (let l = -1; l < a + 1; l++) + if (l >= 0 && l < a && e >= 0 && e < a && 1 === r[l][e]) - 1 === t && (t = l), o = l; + else if (-1 !== t) { + const l = i + t * n, + a = p + e * s, + r = (o - t + 1) * n, + c = s; + r !== n && spawn.mapRect(l, a, r, c), t = -1, o = -1 } - endRow = i; - } else { - if (startRow !== -1) { - const rectX = startX + startRow * cellWidth; - const rectY = startY + j * cellHeight; - const rectWidth = (endRow - startRow + 1) * cellWidth; - const rectHeight = cellHeight; - if (rectWidth !== cellWidth) { - spawn.mapRect(rectX, rectY, rectWidth, rectHeight); - } - startRow = -1; - endRow = -1; - } - } } - } - spawn.mapRect(startX - cellWidth, startY - cellHeight, cellWidth * cells, cellHeight) - spawn.mapRect(startX - cellWidth, startY - cellHeight, cellWidth, cellHeight * cells) - spawn.mapRect(startX + (cells - 1) * cellWidth, startY - cellHeight, cellWidth, cellHeight * (cells + 1)) - spawn.mapRect(startX - cellWidth, startY + (cells - 1) * cellHeight, cellWidth * (cells + 1), cellHeight) - return matrix; - } - - function countAdjacentWalls(matrix, x, y) { - let count = 0; - const directions = [{ - dx: 0, - dy: -1 - }, // Up - { - dx: 1, - dy: 0 - }, // Right - { - dx: 0, - dy: 1 - }, // Down - { - dx: -1, - dy: 0 - } // Left - ]; - for (const direction of directions) { - const neighborX = x + direction.dx; - const neighborY = y + direction.dy; - if (neighborX >= 0 && neighborX < matrix.length && neighborY >= 0 && neighborY < matrix[0].length && matrix[neighborX][neighborY] === 1) { - count++; - } - } - return count; - } - function drawText(x, y, letters) { - const blockSize = 50; - const padding = -30; - const lettersData = { - 'J': [' #### ', ' # ', ' # ', ' # ', ' # # ', ' # # ', ' ## ',], - 'I': [' # ', ' # ', ' # ', ' # ', ' # ', ' # ', ' # ',], - 'N': [' # # ', ' ## # ', ' ## # ', ' # ## ', ' # ## ', ' # # ', ' # # ',], - ' ': [' ', ' ', ' ', ' ', ' ', ' ', ' ',], - 'O': [' ## ', ' # # ', ' # # ', ' # # ', ' # # ', ' # # ', ' ## ',], - 'U': [' # # ', ' # # ', ' # # ', ' # # ', ' # # ', ' # # ', ' ### ',], - 'R': [' #### ', ' # #', ' #### ', ' # # ', ' # # ', ' # #', ' # #',], - 'D': [' ### ', ' # ## ', ' # # ', ' # # ', ' # # ', ' # ## ', ' ### ',], - 'S': [' #### ', ' # ', ' # ', ' ### ', ' ## ', ' # ', ' ##### ',], - 'C': [' ##### ', ' # ', ' # ', ' # ', ' # ', ' # ', ' ##### ',], - 'V': [' # # ', ' # # ', ' # # ', ' # # ', ' # # ', ' # # ', ' # ',], - 'E': [' ##### ', ' # ', ' # ', ' ##### ', ' # ', ' # ', ' ##### ',], - }; - const drawBlock = (x, y) => { - ctx.fillStyle = "black" - ctx.fillRect(x, y, blockSize, blockSize); - }; - const drawLetter = (letter, x, y) => { - const letterData = lettersData[letter]; - if (letterData) { - for (let row = 0; row < letterData.length; row++) { - const rowData = letterData[row]; - for (let col = 0; col < rowData.length; col++) { - const char = rowData[col]; - if (char === '#') { - const blockX = x + (col * (blockSize + padding)); - const blockY = y + (row * (blockSize + padding)); - drawBlock(blockX, blockY); - } - } - } - } - }; - for (let i = 0; i < letters.length; i++) { - const char = letters[i]; - const letterX = x + (i * (blockSize * 5)) - Math.abs(x * 1.5); // Adjust spacing between letters - const letterY = y; - drawLetter(char, letterX, letterY); - } - } + spawn.mapRect(i - n, p - s, n * a, s), spawn.mapRect(i - n, p - s, n, s * a), spawn.mapRect(i + (a - 1) * n, p - s, n, s * (a + 1)), spawn.mapRect(i - n, p + (a - 1) * s, n * (a + 1), s) + }(1e4, -1e3, 1e4, 1e4, 50); }, ruins() { // by SiddhUPe // simulation.enableConstructMode() @@ -28919,6 +28780,465 @@ const level = { spawn.grower(1575, -1525); spawn.grower(1700, -2850); }, + diamagnetism() { + if (localSettings.isHideHUD) localSettings.isHideHUD = false + m.addHealth(Infinity) + document.getElementById("health").style.display = "none" //hide your health bar + document.getElementById("health-bg").style.display = "none" + document.getElementById("defense-bar").style.display = "none" + document.getElementById("damage-bar").style.display = "none" + const futureGuns = ["harpoon", "shotgun", "nail gun", "super balls", "wave", "foam", "laser"]; + const futureGun = Math.floor(Math.random() * futureGuns.length) + b.giveGuns(futureGuns[futureGun], Infinity) + m.setField(2) + m.fieldRegen = 0; + level.trainingText(`diamagnetism by Richard0820
Don't get hit.
Find the portal to the exit.`) + const dodge = []; + const button = level.button(350 - 63, -300) + const door = level.door(750, -275, 50, 125, 125) + const door2 = level.door(750, -525, 50, 125, 125); + const forceOne = forceField(4425, -3925, 525, 3975); + const forceTwo = forceField(1550, -9950, 275, 3300); + const forceThree = forceField(4200, -8725, 750, 4450); + const respawnX = []; + respawnX.push(setRespawn(-50, -625, 825, 375)); + respawnX.push(setRespawn(3225, -3675, 1200, 1000)); + respawnX.push(setRespawn(3575, -5675, 625, 800)); + respawnX.push(setRespawn(775, -4250, 400, 375)); + respawnX.push(setRespawn(2825, -2975, 250, 300)); + respawnX.push(setRespawn(3675, -1125, 325, 250)); + let respawnPoints = { + x: 125, + y: -9575, + } + door2.isClosing = true; + button.isUp = true + level.setPosToSpawn(125, -9575); //normal spawn + level.exit.x = -1825; + level.exit.y = 50; + spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); //bump for level entrance + spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20); //bump for level exit + level.defaultZoom = 1800 + simulation.zoomTransition(level.defaultZoom) + document.body.style.backgroundColor = "#d8dadf"; + alternate(-50, -9050, 425, 100); + const image = new Image() + image.src = "https://raw.githubusercontent.com/Whyisthisnotavalable/image-yy/main/Hotpot-removed.png"; + level.chain(-675, 400, -0.4366271598, true, 20) + level.chain(-1600, 125, 0.5144513131, true, 19) + const portal = portall({ + x: 3825, + y: -1000, + }, + 3 * Math.PI, { + x: 550, + y: -100, + }, + 3 * Math.PI + ); + level.custom = () => { + portal[2].query(); + portal[3].query(); + portal[0].draw(); + portal[1].draw(); + portal[2].draw(); + portal[3].draw(); + forceOne.query() + forceTwo.query() + forceThree.query() + if (input.field && player.position.x < 775 && player.position.x > -50) { + if (m.energy > 0.02) { + m.energy -= 0.01 + } else { + input.field = false + } + } + level.exit.drawAndCheck(); + level.enter.draw(); + button.query() + button.draw() + if (!button.isUp) { + door.isClosing = true; + door2.isClosing = false; + } else if (button.isUp) { + door.isClosing = false; + door2.isClosing = true; + } + door.draw() + door.openClose() + door2.draw() + door2.openClose() + for (let i = 0; i < dodge.length; i++) dodge[i].query(); + for (let i = 0; i < respawnX.length; i++) respawnX[i].query(); + ctx.fillStyle = "gray"; + ctx.fillRect(1175, -6650, 2400, 2375); + ctx.drawImage(image, 1175 + 1200 - 250, -6650 + (2375 / 2) - 250, 500, 500) + if (m.immuneCycle > m.cycle) { + m.energy = m.maxEnergy + Matter.Body.setPosition(player, { + x: respawnPoints.x, + y: respawnPoints.y + }) + } + }; + level.customTopLayer = () => { }; + spawn.mapRect(-100, 0, 5100, 100); + spawn.mapRect(-100, -10000, 5100, 100); + spawn.mapRect(4900, -10000, 100, 10100); + spawn.mapRect(-100, -10000, 100, 9800); + spawn.mapRect(-100, -9525, 450, 100); + spawn.mapRect(725, -300, 100, 400); + spawn.mapRect(725, -10000, 100, 9500); + spawn.mapRect(-100, -300, 925, 100); + spawn.mapRect(800, -675, 3675, 100); + spawn.mapRect(4375, -1425, 100, 850); + spawn.mapRect(1350, -1425, 3125, 100); + spawn.mapRect(1350, -1425, 100, 600); + spawn.mapRect(1350, -925, 2700, 100); + spawn.mapRect(1575, -1175, 2475, 100); + spawn.mapRect(3950, -1175, 100, 350); + spawn.mapRect(4375, -2725, 100, 1400); + spawn.mapRect(775, -2725, 2325, 100); + spawn.mapRect(3200, -2725, 1275, 100); + spawn.mapRect(3200, -3975, 100, 1350); + spawn.mapRect(4375, -3950, 100, 1125); + spawn.mapRect(4375, -3975, 625, 100); + spawn.mapRect(3200, -4325, 100, 450); + spawn.mapRect(3200, -4325, 1600, 100); + spawn.mapRect(4450, -2725, 50, 25); + spawn.mapRect(1125, -3025, 2175, 100); + spawn.mapRect(725, -3925, 2175, 100); + spawn.mapRect(3525, -6700, 100, 2475); + spawn.mapRect(4150, -6700, 100, 2475); + spawn.mapRect(1125, -6700, 2500, 105); + spawn.mapRect(1125, -6700, 100, 2625); + spawn.mapRect(1500, -8775, 100, 2175); + spawn.mapRect(4150, -8775, 100, 1900); + spawn.mapRect(1775, -8775, 2475, 100); + spawn.mapRect(4225, -6700, 50, 25); + spawn.mapRect(4150, -8775, 850, 100); + spawn.mapRect(3600, -2825, 125, 125); + spawn.mapRect(3275, -3050, 125, 125); + spawn.mapRect(3600, -3275, 125, 125); + spawn.mapRect(3300, -3525, 125, 125); + spawn.mapRect(3575, -3725, 900, 125); + spawn.mapRect(4075, -3775, 75, 75); + spawn.mapRect(4225, -3875, 75, 175); + spawn.mapRect(3600, -6625, 100, 100); + spawn.mapRect(4075, -6475, 100, 100); + spawn.mapRect(3600, -6300, 100, 100); + spawn.mapRect(4075, -6175, 100, 100); + spawn.mapRect(3600, -6000, 100, 100); + spawn.mapRect(4075, -5875, 100, 100); + spawn.mapRect(3600, -5700, 100, 100); + spawn.mapRect(4075, -5550, 100, 100); + spawn.mapRect(3600, -5400, 100, 1125); + spawn.mapRect(3675, -5300, 100, 1025); + spawn.mapRect(3750, -5225, 100, 950); + spawn.mapRect(3825, -5150, 100, 875); + spawn.mapRect(3900, -5075, 100, 800); + spawn.mapRect(3975, -5000, 100, 725); + spawn.mapRect(4050, -4925, 125, 650); + spawn.mapRect(4150, -6925, 75, 125); + spawn.mapRect(1775, -8775, 100, 1900); + spawn.mapRect(1775, -9950, 100, 975); + spawn.mapRect(1500, -9950, 100, 975); + spawn.mapRect(1275, -8775, 325, 100); + spawn.mapRect(1200, -7775, 25, 1175); + spawn.mapRect(1250, -7950, 25, 1350); + spawn.mapRect(1300, -8175, 25, 1575); + spawn.mapRect(1350, -8500, 25, 1900); + spawn.mapRect(1400, -8625, 25, 2025); + spawn.mapRect(1450, -8700, 25, 2100); + spawn.mapRect(1150, -7625, 25, 1025); + spawn.mapRect(1125, -4325, 2175, 100); + spawn.mapRect(4250, -925, 150, 100); + spawn.mapRect(575, -225, 175, 50); + spawn.mapRect(575, -50, 175, 75); + spawn.mapRect(-25, 50, 125, 100); + spawn.mapRect(75, 75, 50, 50); + spawn.sniper(3600, -7300); + spawn.sniper(3325, -7475); + spawn.sniper(2825, -7500); + spawn.sniper(2250, -7450); + spawn.sniper(4125, -5150); + spawn.sniper(4100, -5675); + spawn.sniper(4100, -5950); + spawn.sniper(4125, -6325); + spawn.sniper(3875, -6975); + spawn.stabber(4075, -4075); + spawn.stabber(3775, -3950); + spawn.stabber(3500, -3850); + spawn.stabber(4000, -3500); + spawn.stabber(3850, -3125); + spawn.stabber(3450, -3125); + spawn.stabber(4225, -2900); + spawn.hopper(4125, -250); + spawn.hopper(3525, -250); + spawn.hopper(2925, -325); + spawn.hopper(2175, -150); + spawn.hopper(1175, -400); + spawn.mantisBoss(3425, -9350); + spawn.pulsarBoss(1725, -6050, 1); + spawn.pulsarBoss(1800, -4850, 1); + spawn.pulsarBoss(3000, -4825, 1); + spawn.pulsarBoss(2975, -6175, 1); + spawn.spinner(2025, -4050); + spawn.spinner(2125, -2825); + spawn.pulsar(2450, -3775); + spawn.pulsar(2200, -3750); + spawn.pulsar(1900, -3775); + spawn.pulsar(1600, -3725); + spawn.pulsar(1300, -3750); + spawn.pulsar(925, -3725); + spawn.focuser(3925, -2375); + spawn.focuser(1150, -2450); + spawn.focuser(2450, -1675); + spawn.mapVertex(-850, 500, "0 0 500 0 250 500"); + spawn.mapVertex(-1775, 250, "0 0 500 0 250 500"); + spawn.bodyRect(25, -375, 50, 50); + function alternate(x, y, width, height, spacingX = 25, spacingY = 1500, number = 6) { + for (let i = 0; i < number; i++) { + if (i % 2 === 0) { + dodge.push(back(x, y + i * (height + spacingY), width, height, level.enter.x, level.enter.y)) + } else { + dodge.push(back(x + width - spacingX, y + i * (height + spacingY), width, height, level.enter.x, level.enter.y)) + } + } + } + function back(x, y, width, height, x1, y1) { + return { + move: { x: x1, y: y1 }, + min: { x: x, y: y }, + max: { x: x + width, y: y + height }, + width: width, + height: height, + maxHeight: height, + isOn: true, + query() { + if (this.isOn) { + ctx.lineWidth = 5; + ctx.strokeStyle = `hsla(0, 100%, 50%,${0.6 + 0.4 * Math.random()})` + ctx.strokeRect(this.min.x, this.min.y, this.width, this.height) + if (this.height > 0 && Matter.Query.region([player], this).length) { + Matter.Body.setVelocity(player, { x: 0, y: 0 }) + Matter.Body.setPosition(player, { x: this.move.x, y: this.move.y }) + m.energy = m.maxEnergy; + } + } + }, + } + } + function forceField(x, y, width, height) { + return { + min: { x: x, y: y }, + max: { x: x + width, y: y + height }, + width: width, + height: height, + maxHeight: height, + isOn: true, + query() { + if (this.isOn) { + ctx.fillStyle = `rgba(0, 250, 250, 0.55)` + ctx.fillRect(this.min.x, this.min.y, this.width, this.height) + if (this.height > 0 && Matter.Query.region([player], this).length && input.field) { + player.force.y -= 0.015; + m.energy = m.maxEnergy; + } + ctx.fillStyle = `rgba(0, 250, 250)` + ctx.fillRect(this.min.x + this.width * Math.random(), this.min.y, 5, this.height) + } + }, + } + } + function setRespawn(x, y, width, height) { + return { + min: { x: x, y: y }, + max: { x: x + width, y: y + height }, + width: width, + height: height, + maxHeight: height, + isOn: true, + query() { + if (this.isOn) { + ctx.fillStyle = `rgba(0, 250, 0, 0.11)` + ctx.fillRect(this.min.x, this.min.y, this.width, this.height) + if (this.height > 0 && Matter.Query.region([player], this).length) { + m.energy = m.maxEnergy; + respawnPoints.x = this.min.x + (this.width / 2); + respawnPoints.y = this.min.y + (this.height / 2); + } + } + }, + } + } + function portall(centerA, angleA, centerB, angleB) { + const width = 50 + const height = 150 + const mapWidth = 200 + const unitA = Matter.Vector.rotate({ x: 1, y: 0 }, angleA) + const unitB = Matter.Vector.rotate({ x: 1, y: 0 }, angleB) + draw = function () { + ctx.beginPath(); //portal + let v = this.vertices; + ctx.moveTo(v[0].x, v[0].y); + for (let i = 1; i < v.length; ++i) ctx.lineTo(v[i].x, v[i].y); + ctx.fillStyle = this.color + ctx.fill(); + } + query = function (isRemoveBlocks = false) { + if (Matter.Query.collides(this, [player]).length === 0) { //not touching player + if (player.isInPortal === this) player.isInPortal = null + } else if (player.isInPortal !== this) { //touching player + if (m.buttonCD_jump === m.cycle) player.force.y = 0 // undo a jump right before entering the portal + m.buttonCD_jump = 0 //disable short jumps when letting go of jump key + player.isInPortal = this.portalPair + 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); + } else { + // 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); + } + let mag + if (this.portalPair.angle !== 0 && this.portalPair.angle !== Math.PI) { //portal that fires the player up + mag = Math.max(10, Math.min(50, player.velocity.y * 0.8)) + 11 + } else { + mag = Math.max(6, Math.min(50, Vector.magnitude(player.velocity))) + } + let v = Vector.mult(this.portalPair.unit, mag) + Matter.Body.setVelocity(player, v); + // move bots to player + for (let i = 0; i < bullet.length; i++) { + if (bullet[i].botType) { + // Matter.Body.setPosition(bullet[i], this.portalPair.portal.position); + Matter.Body.setPosition(bullet[i], Vector.add(this.portalPair.portal.position, { + x: 250 * (Math.random() - 0.5), + y: 250 * (Math.random() - 0.5) + })); + Matter.Body.setVelocity(bullet[i], { x: 0, y: 0 }); + } + } + if (tech.isHealAttract) { //send heals to next portal + for (let i = 0; i < powerUp.length; i++) { + if (powerUp[i].name === "heal" && Vector.magnitudeSquared(Vector.sub(powerUp[i].position, m.pos)) < 1000000) { + Matter.Body.setPosition(powerUp[i], Vector.add(this.portalPair.portal.position, { x: 500 * (Math.random() - 0.5), y: 500 * (Math.random() - 0.5) })); + } + } + } + } + // if (body.length) { + for (let i = 0, len = body.length; i < len; i++) { + if (body[i] !== m.holdingTarget) { + // body[i].bounds.max.x - body[i].bounds.min.x < 100 && body[i].bounds.max.y - body[i].bounds.min.y < 100 + if (Matter.Query.collides(this, [body[i]]).length === 0) { + if (body[i].isInPortal === this) body[i].isInPortal = null + } else if (body[i].isInPortal !== this) { //touching this portal, but for the first time + if (isRemoveBlocks) { + Matter.Composite.remove(engine.world, body[i]); + body.splice(i, 1); + break + } + body[i].isInPortal = this.portalPair + //teleport + if (this.portalPair.angle % (Math.PI / 2)) { //if left, right up or down + Matter.Body.setPosition(body[i], this.portalPair.portal.position); + } else { //if at some odd angle + Matter.Body.setPosition(body[i], this.portalPair.position); + } + //rotate velocity + let mag + if (this.portalPair.angle !== 0 && this.portalPair.angle !== Math.PI) { //portal that fires the player up + mag = Math.max(10, Math.min(50, body[i].velocity.y * 0.8)) + 11 + } else { + mag = Math.max(6, Math.min(50, Vector.magnitude(body[i].velocity))) + } + let v = Vector.mult(this.portalPair.unit, mag) + Matter.Body.setVelocity(body[i], v); + } + } + } + // } + + //remove block if touching + // if (body.length) { + // touching = Matter.Query.collides(this, body) + // for (let i = 0; i < touching.length; i++) { + // if (touching[i].bodyB !== m.holdingTarget) { + // for (let j = 0, len = body.length; j < len; j++) { + // if (body[j] === touching[i].bodyB) { + // body.splice(j, 1); + // len-- + // Matter.Composite.remove(engine.world, touching[i].bodyB); + // break; + // } + // } + // } + // } + // } + + // if (touching.length !== 0 && touching[0].bodyB !== m.holdingTarget) { + // if (body.length) { + // for (let i = 0; i < body.length; i++) { + // if (body[i] === touching[0].bodyB) { + // body.splice(i, 1); + // break; + // } + // } + // } + // Matter.Composite.remove(engine.world, touching[0].bodyB); + // } + } + + const portalA = composite[composite.length] = Bodies.rectangle(centerA.x, centerA.y, width, height, { + isSensor: true, + angle: angleA, + color: "hsla(197, 100%, 50%,0.7)", + draw: draw, + }); + const portalB = composite[composite.length] = Bodies.rectangle(centerB.x, centerB.y, width, height, { + isSensor: true, + angle: angleB, + color: "hsla(29, 100%, 50%, 0.7)", + draw: draw + }); + const mapA = composite[composite.length] = Bodies.rectangle(centerA.x - 0.5 * unitA.x * mapWidth, centerA.y - 0.5 * unitA.y * mapWidth, mapWidth, height + 10, { + collisionFilter: { + category: cat.map, + mask: cat.bullet | cat.powerUp | cat.mob | cat.mobBullet //cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet + }, + unit: unitA, + angle: angleA, + color: color.map, + draw: draw, + query: query, + lastPortalCycle: 0 + }); + Matter.Body.setStatic(mapA, true); //make static + Composite.add(engine.world, mapA); //add to world + + const mapB = composite[composite.length] = Bodies.rectangle(centerB.x - 0.5 * unitB.x * mapWidth, centerB.y - 0.5 * unitB.y * mapWidth, mapWidth, height + 10, { + collisionFilter: { + category: cat.map, + mask: cat.bullet | cat.powerUp | cat.mob | cat.mobBullet //cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet + }, + unit: unitB, + angle: angleB, + color: color.map, + draw: draw, + query: query, + lastPortalCycle: 0, + }); + Matter.Body.setStatic(mapB, true); //make static + Composite.add(engine.world, mapB); //add to world + + mapA.portal = portalA + mapB.portal = portalB + mapA.portalPair = mapB + mapB.portalPair = mapA + return [portalA, portalB, mapA, mapB] + } + }, trainingTemplate() { //learn to crouch m.addHealth(Infinity) document.getElementById("health").style.display = "none" //hide your health bar diff --git a/js/mob.js b/js/mob.js index 76ba90a..986f725 100644 --- a/js/mob.js +++ b/js/mob.js @@ -12,10 +12,12 @@ const mobs = { } } }, - draw() { + draw() { }, + drawDefault() { ctx.lineWidth = 2; let i = mob.length; while (i--) { + // if (Matter.Query.ray(map, mob[i].position, m.pos).length === 0) { //check if there is a ray between the mob and the player ctx.beginPath(); const vertices = mob[i].vertices; ctx.moveTo(vertices[0].x, vertices[0].y); @@ -25,6 +27,7 @@ const mobs = { ctx.strokeStyle = mob[i].stroke; ctx.fill(); ctx.stroke(); + // } } }, healthBar() { @@ -770,8 +773,8 @@ const mobs = { }) } else { Matter.Body.setVelocity(array[i], { - x: array[i].velocity.x * 0.94 + curlVector.x * 0.06, - y: array[i].velocity.y * 0.94 + curlVector.y * 0.06 + x: array[i].velocity.x * 0.95 + curlVector.x * 0.06, + y: array[i].velocity.y * 0.95 + curlVector.y * 0.06 }) } if (isAntiGravity) array[i].force.y -= 0.8 * simulation.g * array[i].mass diff --git a/js/player.js b/js/player.js index 14d49d3..1c79fd5 100644 --- a/js/player.js +++ b/js/player.js @@ -2542,8 +2542,8 @@ const m = { fieldUpgrades: [{ name: "field emitter", imageNumber: Math.floor(Math.random() * 23), - description: `use energy to deflect mobs -
generate 6 energy per second`, //
100 max energy + description: `initial field
use energy to deflect mobs and throw blocks +
generate 6 energy per second`, //
100 max energy effect: () => { m.hold = function () { if (m.isHolding) { @@ -4174,13 +4174,13 @@ const m = { { name: "wormhole", //wormholes attract blocks and power ups
- description: "use energy to tunnel through a wormhole
+4% chance to duplicate spawned power ups
generate 6 energy per second", //
bullets may also traverse wormholes + description: "use energy to tunnel through a wormhole
+5% chance to duplicate spawned power ups
generate 6 energy per second", //
bullets may also traverse wormholes drain: 0, effect: function () { m.fieldMeterColor = "#bbf" //"#0c5" m.eyeFillColor = m.fieldMeterColor - m.duplicateChance = 0.04 + m.duplicateChance = 0.05 m.fieldRange = 0 powerUps.setPowerUpMode(); //needed after adjusting duplication chance @@ -4366,7 +4366,7 @@ const m = { if (input.field) { if (tech.isWormHolePause) { - const drain = m.fieldRegen + 0.00004 + const drain = m.fieldRegen + 0.000035 if (m.energy > drain) { m.energy -= drain if (m.immuneCycle < m.cycle + 1) m.immuneCycle = m.cycle + 1; //player is immune to damage for 1 cycle @@ -4400,9 +4400,9 @@ const m = { m.grabPowerUp(); //draw possible wormhole if (tech.isWormholeMapIgnore && Matter.Query.ray(map, m.pos, justPastMouse).length !== 0) { - this.drain = (0.06 + 0.006 * Math.sqrt(mag)) * 2 + this.drain = (0.05 + 0.005 * Math.sqrt(mag)) * 2 } else { - this.drain = tech.isFreeWormHole ? 0 : 0.06 + 0.006 * Math.sqrt(mag) + this.drain = tech.isFreeWormHole ? 0 : 0.05 + 0.005 * Math.sqrt(mag) } const unit = Vector.perp(Vector.normalise(sub)) const where = { diff --git a/js/powerup.js b/js/powerup.js index ac88dc6..52d342c 100644 --- a/js/powerup.js +++ b/js/powerup.js @@ -518,7 +518,7 @@ const powerUps = { m.addHealth(heal); if (healOutput > 0) simulation.makeTextLog(`m.health += ${(healOutput).toFixed(3)}`) //
${m.health.toFixed(3)} if (tech.isOverHeal && overHeal > 0) { //tech quenching - const scaledOverHeal = overHeal * 0.9 + const scaledOverHeal = overHeal // * 0.9 m.damage(scaledOverHeal); simulation.makeTextLog(`m.health -= ${(scaledOverHeal).toFixed(3)}`) //
${m.health.toFixed(3)} simulation.drawList.push({ //add dmg to draw queue diff --git a/js/spawn.js b/js/spawn.js index c17d75b..c7dbe55 100644 --- a/js/spawn.js +++ b/js/spawn.js @@ -20,9 +20,9 @@ const spawn = { }, pickList: ["starter", "starter"], fullPickList: [ + "slasher", "slasher", "slasher2", "slasher3", "flutter", "flutter", "flutter", "hopper", "hopper", "hopper", - "slasher", "slasher", "slasher", "stabber", "stabber", "stabber", "springer", "springer", "springer", "shooter", "shooter", @@ -30,8 +30,7 @@ const spawn = { "striker", "striker", "laser", "laser", "pulsar", "pulsar", - "sneaker", "sneaker", - "launcher", "launcherOne", "exploder", "sucker", "sniper", "spinner", "grower", "beamer", "spawner", "ghoster", "focuser" + "sneaker", "launcher", "launcherOne", "exploder", "sucker", "sniper", "spinner", "grower", "beamer", "spawner", "ghoster", "focuser" ], mobTypeSpawnOrder: [], //preset list of mob names calculated at the start of a run by the randomSeed mobTypeSpawnIndex: 0, //increases as the mob type cycles @@ -2437,7 +2436,7 @@ const spawn = { mobs.spawn(x, y, 5, radius, "rgb(0,200,180)"); let me = mob[mob.length - 1]; me.isBoss = true; - me.damageReduction = 0.06 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) + me.damageReduction = 0.08 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) me.accelMag = 0.05; //jump height me.g = 0.003; //required if using this.gravity me.frictionAir = 0.01; @@ -2736,7 +2735,7 @@ const spawn = { me.stroke = "transparent"; //used for drawSneaker me.eventHorizon = 1100; //required for black hole - me.seeAtDistance2 = (me.eventHorizon + 1200) * (me.eventHorizon + 1200); //vision limit is event horizon + me.seeAtDistance2 = (me.eventHorizon + 3000) * (me.eventHorizon + 3000); //vision limit is event horizon me.accelMag = 0.00004 * simulation.accelScale; me.collisionFilter.mask = cat.player | cat.bullet //| cat.body // me.frictionAir = 0.005; @@ -2848,6 +2847,15 @@ const spawn = { ctx.fill(); } this.curl(eventHorizon); + //attract other power ups + for (let i = 0; i < powerUp.length; i++) { //attract heal power ups + const sub = Vector.sub(this.position, powerUp[i].position) + const mag = 0.0015 * Math.min(1, (Vector.magnitude(sub) - 200) / this.eventHorizon) + const attract = Vector.mult(Vector.normalise(sub), mag * powerUp[i].mass) + powerUp[i].force.x += attract.x; + powerUp[i].force.y += attract.y - powerUp[i].mass * simulation.g; //negate gravity + // Matter.Body.setVelocity(powerUp[i], Vector.mult(powerUp[i].velocity, 0.7)); + } } } }, @@ -5493,7 +5501,7 @@ const spawn = { ctx.setLineDash([]); } }, - slasher(x, y, radius = 36 + Math.ceil(Math.random() * 25)) { + slasher(x, y, radius = 33 + Math.ceil(Math.random() * 30)) { mobs.spawn(x, y, 5, radius, "rgb(201,202,225)"); let me = mob[mob.length - 1]; Matter.Body.rotate(me, 2 * Math.PI * Math.random()); @@ -5537,10 +5545,8 @@ const spawn = { this.swordVertex = i } } - // this.laserAngle = 7 / 10 * Math.PI + this.swordVertex / 5 * 2 * Math.PI - Math.PI / 2 this.laserAngle = this.swordVertex / 5 * 2 * Math.PI + 0.6283 this.sword = this.swordGrow - // Matter.Body.setVelocity(this, { x: 0, y: 0 }); this.accelMag = 0 } } @@ -5617,6 +5623,260 @@ const spawn = { ctx.setLineDash([]); } }, + slasher2(x, y, radius = 33 + Math.ceil(Math.random() * 30)) { + mobs.spawn(x, y, 6, radius, "rgb(180,199,245)"); + let me = mob[mob.length - 1]; + Matter.Body.rotate(me, 2 * Math.PI * Math.random()); + me.accelMag = 0.0009 * simulation.accelScale; + me.torqueMagnitude = -0.000012 * me.inertia //* (Math.random() > 0.5 ? -1 : 1); + me.frictionStatic = 0; + me.friction = 0; + me.frictionAir = 0.035; + me.delay = 140 * simulation.CDScale; + me.cd = 0; + me.swordRadius = 0; + me.swordVertex = 1 + me.swordRadiusMax = 275 + 3.5 * simulation.difficulty; + me.swordRadiusGrowRate = me.swordRadiusMax * (0.011 + 0.0002 * simulation.difficulty) + me.isSlashing = false; + me.swordDamage = 0.03 * simulation.dmgScale + me.laserAngle = 3 * Math.PI / 5 + const seeDistance2 = 200000 + spawn.shield(me, x, y); + me.onDamage = function () { }; + me.do = function () { + this.checkStatus(); + this.seePlayerByHistory(15); + this.attraction(); + this.sword() //does various things depending on what stage of the sword swing + }; + me.swordWaiting = function () { + if ( + this.seePlayer.recall && + this.cd < simulation.cycle && + this.distanceToPlayer2() < seeDistance2 && + Matter.Query.ray(map, this.position, this.playerPosRandomY()).length === 0 && + Matter.Query.ray(body, this.position, this.playerPosRandomY()).length === 0 + ) { + this.laserAngle = -Math.PI / 6 + this.sword = this.swordGrow + this.accelMag = 0 + } + } + me.sword = me.swordWaiting //base function that changes during different aspects of the sword swing + me.swordGrow = function () { + this.laserSword(this.vertices[0], this.angle + this.laserAngle); + this.laserSword(this.vertices[3], this.angle + this.laserAngle + Math.PI); + this.swordRadius += this.swordRadiusGrowRate + if (this.swordRadius > this.swordRadiusMax || this.isStunned) { + this.sword = this.swordSlash + this.spinCount = 0 + } + } + me.swordSlash = function () { + this.laserSword(this.vertices[0], this.angle + this.laserAngle); + this.laserSword(this.vertices[3], this.angle + this.laserAngle + Math.PI); + + this.torque += this.torqueMagnitude; + this.spinCount++ + if (this.spinCount > 100 || this.isStunned) { + this.sword = this.swordWaiting + this.swordRadius = 0 + this.accelMag = 0.001 * simulation.accelScale; + this.cd = simulation.cycle + this.delay; + } + } + me.laserSword = function (where, angle) { + const vertexCollision = function (v1, v1End, domain) { + for (let i = 0; i < domain.length; ++i) { + let v = domain[i].vertices; + const len = v.length - 1; + for (let j = 0; j < len; j++) { + results = simulation.checkLineIntersection(v1, v1End, v[j], v[j + 1]); + if (results.onLine1 && results.onLine2) { + const dx = v1.x - results.x; + const dy = v1.y - results.y; + const dist2 = dx * dx + dy * dy; + if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) best = { x: results.x, y: results.y, dist2: dist2, who: domain[i], v1: v[j], v2: v[j + 1] }; + } + } + results = simulation.checkLineIntersection(v1, v1End, v[0], v[len]); + if (results.onLine1 && results.onLine2) { + const dx = v1.x - results.x; + const dy = v1.y - results.y; + const dist2 = dx * dx + dy * dy; + if (dist2 < best.dist2) best = { x: results.x, y: results.y, dist2: dist2, who: domain[i], v1: v[0], v2: v[len] }; + } + } + }; + best = { x: null, y: null, dist2: Infinity, who: null, v1: null, v2: null }; + const look = { x: where.x + this.swordRadius * Math.cos(angle), y: where.y + this.swordRadius * Math.sin(angle) }; + vertexCollision(where, look, body); // vertexCollision(where, look, mob); + vertexCollision(where, look, map); + if (!m.isCloak) vertexCollision(where, look, [playerBody, playerHead]); + if (best.who && (best.who === playerBody || best.who === playerHead) && m.immuneCycle < m.cycle) { + m.immuneCycle = m.cycle + m.collisionImmuneCycles + 60; //player is immune to damage for an extra second + m.damage(this.swordDamage); + simulation.drawList.push({ //add dmg to draw queue + x: best.x, + y: best.y, + radius: this.swordDamage * 1500, + color: "rgba(80,0,255,0.5)", + time: 20 + }); + } + if (best.dist2 === Infinity) best = look; + ctx.beginPath(); //draw beam + ctx.moveTo(where.x, where.y); + ctx.lineTo(best.x, best.y); + ctx.strokeStyle = "rgba(100,100,255,0.1)"; // Purple path + ctx.lineWidth = 15; + ctx.stroke(); + ctx.strokeStyle = "rgba(100,100,255,0.5)"; // Purple path + ctx.lineWidth = 4; + ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]); + ctx.stroke(); // Draw it + ctx.setLineDash([]); + } + }, + slasher3(x, y, radius = 33 + Math.ceil(Math.random() * 30)) { + const sides = 6 + mobs.spawn(x, y, sides, radius, "rgb(180,215,235)"); + let me = mob[mob.length - 1]; + Matter.Body.rotate(me, 2 * Math.PI * Math.random()); + me.accelMag = 0.0005 * simulation.accelScale; + me.frictionStatic = 0; + me.friction = 0; + me.frictionAir = 0.02; + me.delay = 150 * simulation.CDScale; + me.cd = 0; + me.cycle = 0; + me.swordVertex = 1 + me.swordRadiusInitial = radius / 2; + me.swordRadius = me.swordRadiusInitial; + me.swordRadiusMax = 750 + 6 * simulation.difficulty; + me.swordRadiusGrowRateInitial = 1.08 + me.swordRadiusGrowRate = me.swordRadiusGrowRateInitial//me.swordRadiusMax * (0.009 + 0.0002 * simulation.difficulty) + me.isSlashing = false; + me.swordDamage = 0.04 * simulation.dmgScale + me.laserAngle = 3 * Math.PI / 5 + const seeDistance2 = me.swordRadiusMax * me.swordRadiusMax + spawn.shield(me, x, y); + me.onDamage = function () { }; + me.do = function () { + this.checkStatus(); + this.seePlayerByHistory(15); + this.sword() //does various things depending on what stage of the sword swing + }; + me.swordWaiting = function () { + this.attraction(); + if ( + this.seePlayer.recall && + this.cd < simulation.cycle && + this.distanceToPlayer2() < seeDistance2 && + Matter.Query.ray(map, this.position, this.playerPosRandomY()).length === 0 && + Matter.Query.ray(body, this.position, this.playerPosRandomY()).length === 0 + ) { + //find vertex closest to the player + let dist = Infinity + for (let i = 0, len = this.vertices.length; i < len; i++) { + const D = Vector.magnitudeSquared(Vector.sub({ x: this.vertices[i].x, y: this.vertices[i].y }, m.pos)) + if (D < dist) { + dist = D + this.swordVertex = i + } + } + this.laserAngle = this.swordVertex / sides * 2 * Math.PI + Math.PI / sides + this.sword = this.swordGrow + this.cycle = 0 + this.swordRadius = this.swordRadiusInitial + //slow velocity but don't stop + Matter.Body.setVelocity(this, Vector.mult(this.velocity, 0.5)) + //set angular velocity to 50% + // Matter.Body.setAngularVelocity(this, this.angularVelocity * 0.5) + //gently rotate towards the player with a torque, use cross product to decided clockwise or counterclockwise + const laserStartVector = Vector.sub(this.position, this.vertices[this.swordVertex]) + const playerVector = Vector.sub(this.position, m.pos) + const cross = Matter.Vector.cross(laserStartVector, playerVector) + this.torque = 0.00002 * this.inertia * (cross > 0 ? 1 : -1) + } + } + me.sword = me.swordWaiting //base function that changes during different aspects of the sword swing + me.swordGrow = function () { + this.laserSpear(this.vertices[this.swordVertex], this.angle + this.laserAngle); + Matter.Body.setVelocity(this, Vector.mult(this.velocity, 0.9)) + // this.swordRadius += this.swordRadiusGrowRate + this.cycle++ + // this.swordRadius = this.swordRadiusMax * Math.sin(this.cycle * 0.03) + this.swordRadius *= this.swordRadiusGrowRate + + if (this.swordRadius > this.swordRadiusMax) this.swordRadiusGrowRate = 1 / this.swordRadiusGrowRateInitial + // if (this.swordRadius > this.swordRadiusMax) this.swordRadiusGrowRate = -Math.abs(this.swordRadiusGrowRate) + if (this.swordRadius < this.swordRadiusInitial || this.isStunned) { + // this.swordRadiusGrowRate = Math.abs(this.swordRadiusGrowRate) + this.swordRadiusGrowRate = this.swordRadiusGrowRateInitial + this.sword = this.swordWaiting + this.swordRadius = 0 + this.cd = simulation.cycle + this.delay; + } + } + me.laserSpear = function (where, angle) { + const vertexCollision = function (v1, v1End, domain) { + for (let i = 0; i < domain.length; ++i) { + let v = domain[i].vertices; + const len = v.length - 1; + for (let j = 0; j < len; j++) { + results = simulation.checkLineIntersection(v1, v1End, v[j], v[j + 1]); + if (results.onLine1 && results.onLine2) { + const dx = v1.x - results.x; + const dy = v1.y - results.y; + const dist2 = dx * dx + dy * dy; + if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) best = { x: results.x, y: results.y, dist2: dist2, who: domain[i], v1: v[j], v2: v[j + 1] }; + } + } + results = simulation.checkLineIntersection(v1, v1End, v[0], v[len]); + if (results.onLine1 && results.onLine2) { + const dx = v1.x - results.x; + const dy = v1.y - results.y; + const dist2 = dx * dx + dy * dy; + if (dist2 < best.dist2) best = { x: results.x, y: results.y, dist2: dist2, who: domain[i], v1: v[0], v2: v[len] }; + } + } + }; + best = { x: null, y: null, dist2: Infinity, who: null, v1: null, v2: null }; + const look = { x: where.x + this.swordRadius * Math.cos(angle), y: where.y + this.swordRadius * Math.sin(angle) }; + vertexCollision(where, look, body); // vertexCollision(where, look, mob); + vertexCollision(where, look, map); + if (!m.isCloak) vertexCollision(where, look, [playerBody, playerHead]); + if (best.who && (best.who === playerBody || best.who === playerHead)) { + this.swordRadiusGrowRate = 1 / this.swordRadiusGrowRateInitial //!!!! this retracts the sword if it hits the player + + if (m.immuneCycle < m.cycle) { + m.immuneCycle = m.cycle + m.collisionImmuneCycles + 60; //player is immune to damage for an extra second + m.damage(this.swordDamage); + simulation.drawList.push({ //add dmg to draw queue + x: best.x, + y: best.y, + radius: this.swordDamage * 1500, + color: "rgba(80,0,255,0.5)", + time: 20 + }); + } + } + if (best.dist2 === Infinity) best = look; + ctx.beginPath(); //draw beam + ctx.moveTo(where.x, where.y); + ctx.lineTo(best.x, best.y); + ctx.strokeStyle = "rgba(100,100,255,0.1)"; // Purple path + ctx.lineWidth = 15; + ctx.stroke(); + ctx.strokeStyle = "rgba(100,100,255,0.5)"; // Purple path + ctx.lineWidth = 4; + ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]); + ctx.stroke(); // Draw it + ctx.setLineDash([]); + } + }, sneakBoss(x, y, radius = 70) { mobs.spawn(x, y, 5, radius, "transparent"); let me = mob[mob.length - 1]; @@ -5961,10 +6221,7 @@ const spawn = { me.friction = 0; me.frictionAir = 0.05; me.lookTorque = 0.0000025 * (Math.random() > 0.5 ? -1 : 1); - me.fireDir = { - x: 0, - y: 0 - }; + me.fireDir = { x: 0, y: 0 }; me.onDeath = function () { //helps collisions functions work better after vertex have been changed // this.vertices = Matter.Vertices.hull(Matter.Vertices.clockwiseSort(this.vertices)) } @@ -5998,7 +6255,7 @@ const spawn = { me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front me.isVerticesChange = true me.memory = 240; - me.fireFreq = 0.009 + 0.0004 * Math.min(40, simulation.difficulty); //bigger number means more shots per second + me.fireFreq = 0.01 + 0.0005 * Math.min(40, simulation.difficulty); //bigger number means more shots per second me.noseLength = 0; me.fireAngle = 0; me.accelMag = 0.005 * simulation.accelScale; @@ -6027,14 +6284,11 @@ const spawn = { //set direction to turn to fire if (!(simulation.cycle % this.seePlayerFreq)) { this.fireDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position)); - this.fireDir.y -= Math.abs(this.seePlayer.position.x - this.position.x) / 2500; //gives the bullet an arc //was / 1600 + this.fireDir.y -= Math.abs(this.seePlayer.position.x - this.position.x) / 5000; //gives the bullet an arc //was / 1600 } //rotate towards fireAngle const angle = this.angle + Math.PI / 2; - const dot = Vector.dot({ - x: Math.cos(angle), - y: Math.sin(angle) - }, this.fireDir) + const dot = Vector.dot({ x: Math.cos(angle), y: Math.sin(angle) }, this.fireDir) // c = Math.cos(angle) * this.fireDir.x + Math.sin(angle) * this.fireDir.y; const threshold = 0.1; if (dot > threshold) { @@ -6044,12 +6298,9 @@ const spawn = { } else if (this.noseLength > 1.5 && dot > -0.2 && dot < 0.2) { //fire for (let i = 0, len = 2 + 0.07 * simulation.difficulty; i < len; i++) { - spawn.bullet(this.vertices[1].x, this.vertices[1].y, 7 + Math.ceil(this.radius / 25)); - const spread = Vector.rotate({ - x: Math.sqrt(len) + 4, - y: 0 - }, 2 * Math.PI * Math.random()) - const dir = Vector.add(Vector.mult(this.fireDir, 15), spread) + spawn.bullet(this.vertices[1].x, this.vertices[1].y, 10 + Math.ceil(this.radius / 25)); + const spread = Vector.rotate({ x: Math.sqrt(len) + 4, y: 0 }, 2 * Math.PI * Math.random()) + const dir = Vector.add(Vector.mult(this.fireDir, 25), spread) Matter.Body.setVelocity(mob[mob.length - 1], dir); } this.noseLength = 0; @@ -7326,7 +7577,7 @@ const spawn = { mobs.spawn(x, y, 8, radius, "rgba(0,180,180,0.4)"); let me = mob[mob.length - 1]; me.collisionFilter.mask = cat.bullet | cat.player //| cat.mob //| cat.body - me.damageReduction = 0.024 + me.damageReduction = 0.028 Matter.Body.setDensity(me, 0.0001); //normal is 0.001 // me.accelMag = 0.0007 * simulation.accelScale; diff --git a/js/tech.js b/js/tech.js index d59345a..a23769c 100644 --- a/js/tech.js +++ b/js/tech.js @@ -325,7 +325,7 @@ const tech = { tech.hardLanding = 70 tech.isFallingDamage = true; m.setMaxHealth(); - m.addHealth(1 / simulation.healScale) + m.addHealth(2.22 / simulation.healScale) m.skin.tungsten() }, remove() { @@ -3013,7 +3013,10 @@ const tech = { }, { name: "induction brake", - description: `after using ${powerUps.orb.heal()} slow nearby mobs for 15 seconds
spawn ${powerUps.orb.heal(4)}`, + descriptionFunction() { + return `after using ${powerUps.orb.heal()} slow nearby mobs for 15 seconds
spawn ${powerUps.orb.heal(4)}` + }, + // description: `after using ${powerUps.orb.heal()} slow nearby mobs for 15 seconds
spawn ${powerUps.orb.heal(4)}`, maxCount: 1, count: 0, frequency: 1, @@ -3096,7 +3099,10 @@ const tech = { }, { name: "accretion", - description: `${powerUps.orb.heal(1)} follow you, even between levels
spawn ${powerUps.orb.heal(5)}`, + descriptionFunction() { + return `${powerUps.orb.heal(1)} follow you, even between levels
spawn ${powerUps.orb.heal(5)}` + }, + // description: `${powerUps.orb.heal(1)} follow you, even between levels
spawn ${powerUps.orb.heal(5)}`, maxCount: 1, count: 0, frequency: 1, @@ -3270,7 +3276,7 @@ const tech = { }, { name: "Hilbert space", - description: "+91% damage
after a collision enter an alternate reality", + description: "+99% damage
after a collision enter an alternate reality", maxCount: 1, count: 0, frequency: 1, @@ -3280,7 +3286,7 @@ const tech = { return !tech.isResearchReality && !tech.isSwitchReality }, requires: "not Ψ(t) collapse, many-worlds", - damage: 1.91, + damage: 1.99, effect() { tech.damage *= this.damage tech.isCollisionRealitySwitch = true; @@ -3454,7 +3460,10 @@ const tech = { }, { name: "mass production", - description: `tech always have +3 choices to spawn
${powerUps.orb.research(5)} ${powerUps.orb.ammo(8)} or   ${powerUps.orb.heal(8)}`, + descriptionFunction() { + return `tech always have +3 choices to spawn
${powerUps.orb.ammo(8)} ${powerUps.orb.heal(8)}    or ${powerUps.orb.research(5)}` + }, + // description: `tech always have +3 choices to spawn
${powerUps.orb.ammo(8)} ${powerUps.orb.heal(8)}    or ${powerUps.orb.research(5)}`, maxCount: 1, count: 0, frequency: 1, @@ -3502,7 +3511,9 @@ const tech = { }, { name: "heals", - description: `spawn ${powerUps.orb.heal(8)}`, + descriptionFunction() { + return `spawn ${powerUps.orb.heal(8)}` + }, maxCount: 1, count: 0, frequency: 0, @@ -9036,7 +9047,7 @@ const tech = { // }, { name: "return", - description: "return to the introduction level
reduce combat difficulty by 2 levels", + description: "return to the start of the game
reduce combat difficulty by 2 levels", maxCount: 1, count: 0, frequency: 0, @@ -9500,21 +9511,7 @@ const tech = { } }, remove() { - mobs.draw = () => { - ctx.lineWidth = 2; - let i = mob.length; - while (i--) { - ctx.beginPath(); - const vertices = mob[i].vertices; - ctx.moveTo(vertices[0].x, vertices[0].y); - for (let j = 1, len = vertices.length; j < len; ++j) ctx.lineTo(vertices[j].x, vertices[j].y); - ctx.lineTo(vertices[0].x, vertices[0].y); - ctx.fillStyle = mob[i].fill; - ctx.strokeStyle = mob[i].stroke; - ctx.fill(); - ctx.stroke(); - } - } + mobs.draw = mobs.drawDefault } }, { @@ -9546,21 +9543,7 @@ const tech = { } }, remove() { - mobs.draw = () => { - ctx.lineWidth = 2; - let i = mob.length; - while (i--) { - ctx.beginPath(); - const vertices = mob[i].vertices; - ctx.moveTo(vertices[0].x, vertices[0].y); - for (let j = 1, len = vertices.length; j < len; ++j) ctx.lineTo(vertices[j].x, vertices[j].y); - ctx.lineTo(vertices[0].x, vertices[0].y); - ctx.fillStyle = mob[i].fill; - ctx.strokeStyle = mob[i].stroke; - ctx.fill(); - ctx.stroke(); - } - } + mobs.draw = mobs.drawDefault } }, // draw() { diff --git a/todo.txt b/todo.txt index d759548..c95e84f 100644 --- a/todo.txt +++ b/todo.txt @@ -1,15 +1,33 @@ ******************************************************** NEXT PATCH ************************************************** -new community levels: - tlinat by Richard0820 - ruins by SiddhUPe +new community training level diamagnetism by Richard0820 + it's at the end of the training levels + start training by click the top right button at the load screen -tech: mass production - tech have +3 choices to spawn ammo, research, or heals +slasher mob variant with 2 laser swords +slasher mob variant with a laser spear + +suckerBoss pulls in powerUps and makes them orbit better +shooterBoss fires faster and larger bullets + +wormhole 4 -> 5% duplication, and a 10% reduction in energy cost +drones fire faster and aim more accurately +quenching gives 10% more max health and harm +snake tail mobs have 15% less health +tungsten carbide properly gives 222 health in addition to the bonus max health *********************************************************** TODO ***************************************************** -make a mob similar to slasher - because it's just a very well made mob. +use cross product rotation for other mobs? + snipers, shooters? + //gently rotate towards the player with a torque, use cross product to decided clockwise or counterclockwise + const laserStartVector = Vector.sub(this.position, this.vertices[this.swordVertex]) + const playerVector = Vector.sub(this.position, m.pos) + const cross = Matter.Vector.cross(laserStartVector, playerVector) + this.torque = 0.00002 * this.inertia * (cross > 0 ? 1 : -1) + +block manufacturing - molecular assembler tech +Holding r-click will create a slowly increasing in size block, which will be thrown on release super-bot: fires super balls @@ -24,8 +42,6 @@ tech: after a needle hits a mobs reset your fire CD? 2x damage for each consecutive mob hit? -improve flatland performance? - mob non-combat behaviors, like Rain World gathering blocks @@ -62,10 +78,6 @@ use ephemera to replace some bad code damage and defense bars disable and enable ephemera with settings -drones target anything that moves: speed > 1 - including player, blocks?, mobs, power ups - maybe target the fastest mobs? - perfect diamagnatism - invulnerable while field is active? also drain energy while field is active? @@ -75,11 +87,6 @@ mobs attack mines tech circular polarization - wave gun bullets move in a circle -tech: choose next map by name after exiting current map - use modified tech selection code? - this might be too much work without much reward - JUNK only? or maybe combine with other buff - Tech: relativity Simulation speed scales with movement speed. When still, time moves at 0.4 speed, at full walking speed it’s 1. (So if you’re falling or something and you move faster the simulation will be faster than usual) Also a damage and/or defense boost to make it worth using @@ -94,7 +101,6 @@ extend brainstorming animation timers to fps cap? perfect diamagnatism could bounce on mobs, or even map elements? could work like a rocket jump? - tech: Bose Einstein condensate - freezes enemies in pilot wave, and drains some energy? make super balls with Zectron deflectable with field @@ -103,17 +109,8 @@ make super balls with Zectron deflectable with field set mob health bar colors based on status effects? make mob damage immunity a mob status effect? -physics notes: add link to double slit content - https://www.youtube.com/watch?v=v_uBaBuarEM - tech: rail gun area damage effect, but for all harpoon mode -laser momentum pushed back on player? - might just be annoying - -JUNK - overwrite mob draw function so mobs only draw if they can connect a ray from player to mob - gonna cause lag? - mob status effect - vulnerability mobs take 4x damage for __ time afterwards mobs go back to normal damage taken @@ -129,8 +126,6 @@ tech: sporangium that grow little trees the trees have an area of effect damage for about 6-10 seconds maybe something similar to radioactive drones, but maybe a few smaller shapes -harpoon tech that makes auto aim work much better - hookBoss fires a hook that pulls player towards it hook does a bit of damage player targeted unless cloaking @@ -213,13 +208,9 @@ Tech:when relay switch/flip flop is on, turn ammo powerups into boosts, when rel JUNK: what the golf? trying to throw a block throws you instead -look for other tech that would benefit from a 3rd line of description text - tech for lens - you can only fire through the lens and some buff? damage or energy? -hopMom fight make platforming with hop bullets harder? - complete blowSuckBoss... or don't tech: laser reflections increase damage @@ -227,14 +218,6 @@ tech: laser reflections increase damage JUNK tech different effects based on night or day use system time -buffing your deflecting for 1 second after pressing the field button - 2 second cooldown on the effect to prevent spamming it - buff: giving energy or doing damage makes sense - maybe this could be a rework for bremstralung - -replace field descriptions with a function call so they can have dynamic text - add in dynamic coupling text as a 4th line - Boss that shoots out a ring of bullets, then after a few seconds it gravitates the bullets back coupling @@ -404,12 +387,6 @@ super balls do more damage after bouncing? how to check for bounce? maybe just increases damage after hitting a mob -Make environmental damages also damage mobs -So if a mob passes through laser, it gets damaged - -dark mode: - look at Tinyfolks, 20 minutes till dawn - super short range foam that acts like flame thrower high fire rate short life spawn @@ -428,8 +405,7 @@ laser tech where bots move around and follow you while firing lasers in the dire beam is similar to diffuse beam -block manufacturing - molecular assembler tech -Holding r-click will create a slowly increasing in size block, which will be thrown on release + double research