landgreen / n-gon

2-d physics rogue-lite platformer shooter
https://landgreen.github.io/n-gon/
GNU General Public License v3.0
144 stars 208 forks source link

New training level: diamagnetism #58

Closed Whyisthisnotavalable closed 1 year ago

Whyisthisnotavalable commented 1 year ago
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(`<strong>Don't get hit.</strong><br> 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]
    }
},
Whyisthisnotavalable commented 1 year ago

You once said that high quality training maps would be accepted.

Whyisthisnotavalable commented 1 year ago

So here it is.

Whyisthisnotavalable commented 1 year ago

By the way, you should fix portals teleporting doors, if they come into contact.

landgreen commented 1 year ago

Ok, looks fun. It's way too hard though, but I guess since it will go at the end of the training levels it's alright.

Whyisthisnotavalable commented 1 year ago

Perhaps when people add more community training levels, you could have it only appear if the community maps thing is selected.

landgreen commented 1 year ago

yeah, although I think for now I'll just make sure training levels are all high quality.