portal level work in progress

This commit is contained in:
landgreen
2020-07-18 11:37:37 -07:00
parent c63d0ac5f0
commit 08e09b59c4
8 changed files with 552 additions and 217 deletions

View File

@@ -740,6 +740,7 @@ const b = {
const DIST = Vector.magnitude(TARGET_VECTOR);
if (DIST < closeDist) {
if (DIST < 60) { //eat the power up if close enough
powerUps.onPickUp();
powerUp[i].effect();
Matter.World.remove(engine.world, powerUp[i]);
powerUp.splice(i, 1);
@@ -988,6 +989,7 @@ const b = {
const dir = mech.angle;
const RADIUS = (12 + 4 * Math.random())
bullet[me] = Bodies.polygon(position.x, position.y, 4, RADIUS, {
isBot: true,
angle: dir,
friction: 0,
frictionStatic: 0,
@@ -1043,6 +1045,7 @@ const b = {
const dir = mech.angle;
const RADIUS = (10 + 5 * Math.random())
bullet[me] = Bodies.polygon(position.x, position.y, 6, RADIUS, {
isBot: true,
angle: dir,
friction: 0,
frictionStatic: 0,
@@ -1098,6 +1101,7 @@ const b = {
const dir = mech.angle;
const RADIUS = 21
bullet[me] = Bodies.polygon(position.x, position.y, 5, RADIUS, {
isBot: true,
angle: dir,
friction: 0,
frictionStatic: 0,
@@ -1288,6 +1292,7 @@ const b = {
const dir = mech.angle;
const RADIUS = (7 + 2 * Math.random())
bullet[me] = Bodies.polygon(position.x, position.y, 4, RADIUS, {
isBot: true,
angle: dir,
friction: 0,
frictionStatic: 0,
@@ -1364,6 +1369,7 @@ const b = {
const dir = mech.angle;
const RADIUS = (14 + 6 * Math.random())
bullet[me] = Bodies.polygon(position.x, position.y, 3, RADIUS, {
isBot: true,
angle: dir,
friction: 0,
frictionStatic: 0,
@@ -1391,11 +1397,6 @@ const b = {
},
onEnd() {},
do() {
//move in a circle
// const radius = 1.5
// this.offPlayer.x -= radius * Math.cos(game.cycle * 0.02)
// this.offPlayer.y -= radius * Math.sin(game.cycle * 0.02)
const playerPos = Vector.add(Vector.add(this.offPlayer, mech.pos), Vector.mult(player.velocity, 20)) //also include an offset unique to this bot to keep many bots spread out
const farAway = Math.max(0, (Vector.magnitude(Vector.sub(this.position, playerPos))) / this.followRange) //linear bounding well
const mag = Math.min(farAway, 4) * this.mass * this.acceleration
@@ -1405,7 +1406,6 @@ const b = {
x: this.velocity.x * 0.95,
y: this.velocity.y * 0.95
});
//find targets
if (!(game.cycle % this.lookFrequency) && !mech.isStealth) {
this.lockedOn = null;
@@ -1420,7 +1420,6 @@ const b = {
this.lockedOn = mob[i]
}
}
//randomize position relative to player
if (Math.random() < 0.15) {
this.offPlayer = {
@@ -1429,7 +1428,6 @@ const b = {
}
}
}
//hit target with laser
if (this.lockedOn && this.lockedOn.alive && mech.energy > 0.15) {
mech.energy -= 0.0014 * mod.isLaserDiode
@@ -1526,12 +1524,11 @@ const b = {
fire() {
const me = bullet.length;
const dir = mech.angle + (Math.random() - 0.5) * ((mech.crouch) ? 0.01 : 0.1);
bullet[me] = Bodies.rectangle(mech.pos.x + 23 * Math.cos(mech.angle), mech.pos.y + 23 * Math.sin(mech.angle), 20 * mod.bulletSize, 6 * mod.bulletSize, b.fireAttributes(dir));
bullet[me] = Bodies.rectangle(mech.pos.x + 23 * Math.cos(mech.angle), mech.pos.y + 23 * Math.sin(mech.angle), 20 * mod.bulletSize * mod.highCaliber, 6 * mod.bulletSize, b.fireAttributes(dir));
//fire delay decreases as you hold fire, down to 3 from 15
if (this.nextFireCycle + 1 < mech.cycle) this.startingHoldCycle = mech.cycle //reset if not constantly firing
const CD = Math.max(11 - 0.06 * (mech.cycle - this.startingHoldCycle), 2) //CD scales with cycles fire is held down
const CD = Math.max(11 - 0.06 * (mech.cycle - this.startingHoldCycle), 2) * mod.highCaliber //CD scales with cycles fire is held down
this.nextFireCycle = mech.cycle + CD * b.fireCD //predict next fire cycle if the fire button is held down
b.fireProps(CD, mech.crouch ? 38 : 34, dir, me); //cd , speed
// b.fireProps(mech.crouch ? 7 : 4, mech.crouch ? 40 : 34, dir, me); //cd , speed
@@ -1583,8 +1580,6 @@ const b = {
player.force.y -= knock * Math.sin(mech.angle) * 0.3 //reduce knock back in vertical direction to stop super jumps
}
b.muzzleFlash(35);
if (mod.isNailShot) {
for (let i = 0; i < 14; i++) {
@@ -1635,8 +1630,8 @@ const b = {
num: 5,
isEasyToAim: true,
fire() {
const SPEED = mech.crouch ? 40 : 30
mech.fireCDcycle = mech.cycle + Math.floor((mech.crouch ? 28 : 20) * b.fireCD); // cool down
const SPEED = mech.crouch ? 43 : 32
mech.fireCDcycle = mech.cycle + Math.floor((mech.crouch ? 25 : 18) * b.fireCD); // cool down
if (mod.oneSuperBall) {
let dir = mech.angle
const me = bullet.length;
@@ -1649,7 +1644,7 @@ const b = {
// Matter.Body.setDensity(bullet[me], 0.0001);
bullet[me].endCycle = game.cycle + Math.floor((300 + 60 * Math.random()) * mod.isBulletsLastLonger);
bullet[me].minDmgSpeed = 0;
bullet[me].restitution = 0.999;
bullet[me].restitution = 1;
bullet[me].friction = 0;
bullet[me].do = function () {
this.force.y += this.mass * 0.001;
@@ -1663,7 +1658,7 @@ const b = {
let dir = mech.angle - SPREAD * (mod.superBallNumber - 1) / 2;
for (let i = 0; i < mod.superBallNumber; i++) {
const me = bullet.length;
bullet[me] = Bodies.polygon(mech.pos.x + 30 * Math.cos(mech.angle), mech.pos.y + 30 * Math.sin(mech.angle), 12, 7 * mod.bulletSize, b.fireAttributes(dir, false));
bullet[me] = Bodies.polygon(mech.pos.x + 30 * Math.cos(mech.angle), mech.pos.y + 30 * Math.sin(mech.angle), 12, 7.5 * mod.bulletSize, b.fireAttributes(dir, false));
World.add(engine.world, bullet[me]); //add bullet to world
Matter.Body.setVelocity(bullet[me], {
x: SPEED * Math.cos(dir),
@@ -1927,7 +1922,7 @@ const b = {
name: "missiles",
description: "launch missiles that <strong>accelerate</strong> towards <strong>mobs</strong><br><strong class='color-e'>explodes</strong> when near target",
ammo: 0,
ammoPack: 4,
ammoPack: 5,
have: false,
isEasyToAim: true,
fireCycle: 0,
@@ -2094,7 +2089,7 @@ const b = {
bullet[me].restitution = 0.2;
bullet[me].friction = 0.3;
bullet[me].endCycle = Infinity
bullet[me].explodeRad = 440 + Math.floor(Math.random() * 30);
bullet[me].explodeRad = 450 + Math.floor(Math.random() * 30);
bullet[me].onEnd = function () {
b.explosion(this.position, this.explodeRad); //makes bullet do explosive damage at end
@@ -2218,7 +2213,7 @@ const b = {
bullet[me].restitution = 0;
bullet[me].minDmgSpeed = 0;
bullet[me].damageRadius = 100;
bullet[me].maxDamageRadius = (425 + 125 * Math.random()) * (mod.isNeutronImmune ? 1.2 : 1)
bullet[me].maxDamageRadius = (435 + 150 * Math.random()) * (mod.isNeutronImmune ? 1.2 : 1)
bullet[me].stuckTo = null;
bullet[me].stuckToRelativePosition = null;
bullet[me].onDmg = function () {};
@@ -2283,8 +2278,6 @@ const b = {
} else {
const bodyCollisions = Matter.Query.collides(this, body)
if (bodyCollisions.length) {
if (!bodyCollisions[0].bodyA.isNotSticky) {
onCollide(this)
this.stuckTo = bodyCollisions[0].bodyA
@@ -2329,7 +2322,6 @@ const b = {
this.endCycle = 0;
} else {
//aoe damage to player
if (!mod.isNeutronImmune && Vector.magnitude(Vector.sub(player.position, this.position)) < this.damageRadius) {
const DRAIN = 0.0015
if (mech.energy > DRAIN) {
@@ -2380,7 +2372,7 @@ const b = {
x: speed * Math.cos(mech.angle),
y: speed * Math.sin(mech.angle)
}, 0, mod.isMineAmmoBack)
mech.fireCDcycle = mech.cycle + Math.floor((mech.crouch ? 60 : 20) * b.fireCD); // cool down
mech.fireCDcycle = mech.cycle + Math.floor((mech.crouch ? 50 : 25) * b.fireCD); // cool down
}
},
{
@@ -2508,7 +2500,7 @@ const b = {
name: "drones",
description: "deploy drones that <strong>crash</strong> into mobs<br>crashes reduce their <strong>lifespan</strong> by 1 second",
ammo: 0,
ammoPack: 14,
ammoPack: 15,
have: false,
isEasyToAim: true,
fire() {
@@ -2621,7 +2613,10 @@ const b = {
this.force.y += this.mass * 0.0003 / this.charge; // low gravity that scales with charge
}
}
if (mod.isRailTimeSlow) {
game.fpsCap = game.fpsCapDefault
game.fpsInterval = 1000 / game.fpsCap;
}
Matter.Body.scale(this, 8000, 8000) // show the bullet by scaling it up (don't judge me... I know this is a bad way to do it)
this.endCycle = game.cycle + 140
@@ -2672,7 +2667,12 @@ const b = {
let chargeRate = (mech.crouch) ? 0.975 : 0.987
chargeRate *= Math.pow(b.fireCD, 0.03)
this.charge = this.charge * chargeRate + (1 - chargeRate) // this.charge converges to 1
mech.energy -= (this.charge - lastCharge) * 0.28 //energy drain is proportional to charge gained, but doesn't stop normal mech.fieldRegen
if (mod.isRailTimeSlow) {
game.fpsCap = 30 //new fps
game.fpsInterval = 1000 / game.fpsCap;
} else {
mech.energy -= (this.charge - lastCharge) * 0.28 //energy drain is proportional to charge gained, but doesn't stop normal mech.fieldRegen
}
//draw targeting
let best;

View File

@@ -205,6 +205,7 @@ function collisionChecks(event) {
if (obj.classType === "bullet" && obj.speed > obj.minDmgSpeed) {
// const dmg = b.dmgScale * (obj.dmg + 0.15 * obj.mass * Vector.magnitude(Vector.sub(mob[k].velocity, obj.velocity)));
let dmg = b.dmgScale * (obj.dmg + 0.15 * obj.mass * Vector.magnitude(Vector.sub(mob[k].velocity, obj.velocity)))
console.log(dmg)
if (mod.isCrit && !mob[k].seePlayer.recall && !mob[k].shield) dmg *= 5
mob[k].foundPlayer();
mob[k].damage(dmg);

View File

@@ -39,6 +39,7 @@ const game = {
b.bulletDraw();
b.bulletDo();
game.drawCircle();
level.customTopLayer();
// game.clip();
ctx.restore();
game.drawCursor();
@@ -67,6 +68,7 @@ const game = {
game.draw.testing();
game.drawCircle();
game.constructCycle()
level.customTopLayer();
ctx.restore();
game.testingOutput();
game.drawCursor();
@@ -691,6 +693,9 @@ const game = {
mech.holdingTarget.collisionFilter.category = 0;
mech.holdingTarget.collisionFilter.mask = 0;
}
//set fps back to default
game.fpsCap = game.fpsCapDefault
game.fpsInterval = 1000 / game.fpsCap;
},
getCoords: {
//used when building maps, outputs a draw rect command to console, only works in testing mode
@@ -735,12 +740,16 @@ const game = {
x: level.enter.x + 50,
y: level.enter.y - 20
});
// Matter.Body.setPosition(player, {
// x: player.position.x,
// y: -7000
// });
// game.noCameraScroll()
// move bots
for (let i = 0; i < bullet.length; i++) {
if (bullet[i].isBot) {
Matter.Body.setPosition(bullet[i], player.position);
Matter.Body.setVelocity(bullet[i], {
x: 0,
y: 0
});
}
}
if (game.difficultyMode === 2) mech.damage(0.3);
if (game.difficultyMode === 1) mech.damage(0.1);
mech.energy = 0;

View File

@@ -12,18 +12,18 @@ const level = {
if (build.isURLBuild && level.levelsCleared === 0) build.onLoadPowerUps();
if (level.levelsCleared === 0) { //this code only runs on the first level
// level.difficultyIncrease(4)
// game.enableConstructMode() //used to build maps in testing mode
game.enableConstructMode() //used to build maps in testing mode
// game.zoomScale = 1000;
// game.setZoom();
// mech.isStealth = true;
// mod.giveMod("bot fabrication");
// mod.giveMod("nail-bot");
// b.giveGuns("ice IX")
// mech.setField("plasma torch")
level.intro(); //starting level
// level.sewers();
// level.testing();
// level.template()
// level.bosses();
// level.stronghold()
// level.intro(); //starting level
level.testChamber()
// level.sewers();
// level.satellite();
// level.skyscrapers();
// level.aerie();
@@ -31,7 +31,9 @@ const level = {
// level.warehouse();
// level.highrise();
// level.office();
// level.bosses();
// level.template()
// level.stronghold() //fan level
} else {
spawn.setSpawnList(); //picks a couple mobs types for a themed random mob spawns
// spawn.pickList = ["focuser", "focuser"]
@@ -43,24 +45,12 @@ const level = {
game.setZoom();
level.addToWorld(); //add bodies to game engine
game.draw.setPaths();
for (let i = 0; i < mod.laserBotCount; i++) {
b.laserBot()
}
for (let i = 0; i < mod.nailBotCount; i++) {
b.nailBot()
}
for (let i = 0; i < mod.foamBotCount; i++) {
b.foamBot()
}
for (let i = 0; i < mod.boomBotCount; i++) {
b.boomBot()
}
for (let i = 0; i < mod.plasmaBotCount; i++) {
b.plasmaBot()
}
for (let i = 0; i < mod.laserBotCount; i++) b.laserBot()
for (let i = 0; i < mod.nailBotCount; i++) b.nailBot()
for (let i = 0; i < mod.foamBotCount; i++) b.foamBot()
for (let i = 0; i < mod.boomBotCount; i++) b.boomBot()
for (let i = 0; i < mod.plasmaBotCount; i++) b.plasmaBot()
if (mod.isArmorFromPowerUps) {
// for (let i = 0; i < powerUps.totalPowerUps; i++) {}
mech.maxHealth += 0.05 * powerUps.totalPowerUps
if (powerUps.totalPowerUps) game.makeTextLog("<span style='font-size:115%;'> max health increased by " + (0.05 * powerUps.totalPowerUps * 100).toFixed(0) + "%</span>", 300)
}
@@ -69,140 +59,249 @@ const level = {
mech.displayHealth();
}
},
custom() {},
customTopLayer() {},
//******************************************************************************************************************
//******************************************************************************************************************
//******************************************************************************************************************
//******************************************************************************************************************
rotor(x, y, rotate = 0, radius = 900, width = 50, density = 0.0005) {
const rotor1 = Matter.Bodies.rectangle(x, y, width, radius, {
density: density,
isNotSticky: true,
isNotHoldable: true
});
const rotor2 = Matter.Bodies.rectangle(x, y, width, radius, {
angle: Math.PI / 2,
density: density,
isNotSticky: true,
isNotHoldable: true
});
rotor = Body.create({ //combine rotor1 and rotor2
parts: [rotor1, rotor2],
restitution: 0,
collisionFilter: {
category: cat.body,
mask: cat.body | cat.mob | cat.mobBullet | cat.mobShield | cat.powerUp | cat.player | cat.bullet
},
});
Matter.Body.setPosition(rotor, {
x: x,
y: y
});
World.add(engine.world, [rotor]);
body[body.length] = rotor1
body[body.length] = rotor2
portal(centerA, angleA, centerB, angleB) {
const width = 30
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)
setTimeout(function () {
rotor.collisionFilter.category = cat.body;
rotor.collisionFilter.mask = cat.body | cat.player | cat.bullet | cat.mob | cat.mobBullet //| cat.map
}, 1000);
const constraint = Constraint.create({ //fix rotor in place, but allow rotation
pointA: {
x: x,
y: y
},
bodyB: rotor
});
World.add(engine.world, constraint);
if (rotate) {
rotor.rotate = function () {
if (!mech.isBodiesAsleep) {
Matter.Body.applyForce(rotor, {
x: rotor.position.x + 100,
y: rotor.position.y + 100
}, {
x: rotate * rotor.mass,
y: 0
})
} else {
Matter.Body.setAngularVelocity(rotor, 0);
}
draw = function () {
ctx.beginPath(); //portal
sensor = this.vertices;
ctx.moveTo(sensor[0].x, sensor[0].y);
for (let i = 1; i < sensor.length; ++i) {
ctx.lineTo(sensor[i].x, sensor[i].y);
}
ctx.fillStyle = this.color
ctx.fill();
}
composite[composite.length] = rotor
return rotor
},
button(x, y, width = 70) {
spawn.mapVertex(x + 35, y + 2, "70 10 -70 10 -40 -10 40 -10");
return {
isUp: false,
min: {
x: x,
y: y - 15
},
max: {
x: x + width,
y: y - 5
},
width: width,
height: 20,
query() {
if (Matter.Query.region(body, this).length === 0 && Matter.Query.region([player], this).length === 0) {
this.isUp = true;
query = function () {
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
//teleport
player.isInPortal = this.portalPair
Matter.Body.setPosition(player, this.portalPair.position);
//rotate velocity
// const unit = Vector.normalise(Vector.rotate(player.velocity, this.angle - this.portalPair.angle + Math.PI)) //rotate and flip velocity
// const mag = Math.max(20, Math.min(50, Vector.magnitude(player.velocity))) //20 is lowest speed, 50 is highest speed
// const v = Vector.mult(unit, mag)
let mag
if (this.angle === -Math.PI / 2) {
//portal that fires the player up
mag = Math.max(10, Math.min(50, player.velocity.y * 0.8)) + 11
} else {
this.isUp = false;
mag = Math.max(3, Math.min(50, Vector.magnitude(player.velocity)))
}
},
draw() {
ctx.fillStyle = "hsl(0, 100%, 70%)"
if (this.isUp) {
ctx.fillRect(this.min.x, this.min.y - 10, this.width, 20)
} else {
ctx.fillRect(this.min.x, this.min.y, this.width, 25)
}
}
}
},
hazard(x, y, width, height, damage = 0.0005, color = "hsl(160, 100%, 35%)") {
return {
min: {
x: x,
y: y
},
max: {
x: x + width,
y: y + height
},
width: width,
height: height,
maxHeight: height,
query() {
if (this.height > 0 && Matter.Query.region([player], this).length && !mech.isStealth) {
mech.damage(damage)
const drain = 0.005
if (mech.energy > drain) mech.energy -= drain
}
},
draw() {
ctx.fillStyle = color
ctx.fillRect(this.min.x, this.min.y, this.width, this.height)
},
level(isFill) {
const growSpeed = 1
if (isFill) {
if (this.height < this.maxHeight) {
this.height += growSpeed
this.min.y -= growSpeed
this.max.y = this.min.y + this.height
console.log(mag)
const v = Vector.mult(this.portalPair.unit, mag)
Matter.Body.setVelocity(player, v);
mech.buttonCD_jump = 0 //disable short jumps when letting go of jump key
// move bots to follow player
for (let i = 0; i < bullet.length; i++) {
if (bullet[i].isBot) {
Matter.Body.setPosition(bullet[i], this.portalPair.portal.position);
Matter.Body.setVelocity(bullet[i], {
x: 0,
y: 0
});
}
} else if (this.height > 0) {
this.height -= growSpeed
this.min.y += growSpeed
this.max.y = this.min.y + this.height
}
}
}
const portalA = Bodies.rectangle(centerA.x, centerA.y, width, height, {
isSensor: true,
angle: angleA,
color: "hsla(197, 100%, 50%,0.7)",
draw: draw,
});
const portalB = Bodies.rectangle(centerB.x, centerB.y, width, height, {
isSensor: true,
angle: angleB,
color: "hsla(29, 100%, 50%, 0.7)",
draw: draw
});
const mapA = Bodies.rectangle(centerA.x - 0.5 * unitA.x * mapWidth, centerA.y - 0.5 * unitA.y * mapWidth, mapWidth, height + 100, {
collisionFilter: {
category: cat.map,
mask: cat.body | 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: game.draw.mapFill,
draw: draw,
query: query,
lastPortalCycle: 0
});
Matter.Body.setStatic(mapA, true); //make static
World.add(engine.world, mapA); //add to world
const mapB = Bodies.rectangle(centerB.x - 0.5 * unitB.x * mapWidth, centerB.y - 0.5 * unitB.y * mapWidth, mapWidth, height + 100, {
collisionFilter: {
category: cat.map,
mask: cat.body | 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: game.draw.mapFill,
draw: draw,
query: query,
lastPortalCycle: 0
});
Matter.Body.setStatic(mapB, true); //make static
World.add(engine.world, mapB); //add to world
mapA.portal = portalA
mapB.portal = portalB
mapA.portalPair = mapB
mapB.portalPair = mapA
return [portalA, portalB, mapA, mapB]
},
testChamber() {
const portal = level.portal({
x: 2500,
y: -100
}, Math.PI, { //left
x: 2500,
y: -3100
}, Math.PI) //left
const portal2 = level.portal({
x: 100,
y: -2150
}, -Math.PI / 2, { //up
x: 1300,
y: -2150
}, -Math.PI / 2) //up
level.custom = () => {
level.playerExitCheck();
portal[2].query()
portal[3].query()
portal2[2].query()
portal2[3].query()
};
level.customTopLayer = () => {
portal[0].draw();
portal[1].draw();
portal[2].draw();
portal[3].draw();
portal2[0].draw();
portal2[1].draw();
portal2[2].draw();
portal2[3].draw();
};
if (false) {
level.setPosToSpawn(0, -50); //lower spawn
level.exit.y = level.enter.y - 550;
level.fillBG.push({
x: -300,
y: -1000,
width: 650,
height: 500,
color: "#d4f4f4"
});
} else {
level.setPosToSpawn(0, -600); //upper spawn
level.exit.y = level.enter.y + 550;
level.fillBG.push({
x: -300,
y: -500,
width: 650,
height: 500,
color: "#d4f4f4"
});
}
spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
level.exit.x = level.enter.x;
spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20);
level.defaultZoom = 1800
game.zoomTransition(level.defaultZoom)
document.body.style.backgroundColor = "#dcdcde";
// powerUps.spawnStartingPowerUps(1475, -1175);
// spawn.debris(750, -2200, 3700, 16); //16 debris per level
//outer wall
spawn.mapRect(-500, -3800, 200, 4000); //left map wall
spawn.mapRect(2500, -2975, 200, 2375); //right map middle wall
spawn.mapRect(-400, -3800, 3100, 200); //map ceiling
spawn.mapRect(-400, 0, 3100, 200); //floor
//entrance
spawn.mapRect(300, -550, 50, 350); //right entrance wall
spawn.mapRect(-400, -550, 3000, 50); //ceiling
//entrance clutter
const xPos = shuffle([550, 1100, 1850]);
spawn.mapRect(xPos[0], -350, 400, 100);
spawn.mapRect(xPos[1], -350, 300, 400);
spawn.mapRect(xPos[2], -150, 300, 200);
//exit
spawn.mapRect(-400, -1050, 750, 50);
spawn.mapRect(300, -1050, 50, 300);
//portal bottom
spawn.mapRect(2500, -700, 200, 540); //right portal wall
spawn.mapRect(2525, -200, 175, 250); //right portal back wall
//portal top
spawn.mapRect(1400, -3000, 1300, 50); //floor
spawn.mapRect(2500, -3700, 200, 540); //right portal wall
spawn.mapRect(2525, -3200, 175, 250); //right portal back wall
// spawn.mapRect(700, -3250, 775, 350);
spawn.mapRect(0, -3250, 1450, 50);
spawn.mapRect(1400, -3250, 50, 300);
// spawn.mapRect(-350, -2875, 175, 325);
spawn.mapRect(-150, -3000, 150, 50);
spawn.mapRect(-350, -2750, 175, 200);
//portal 2
spawn.mapRect(-300, -2600, 300, 700);
spawn.mapRect(-25, -1975, 250, 75);
spawn.mapRect(1400, -2600, 300, 700);
spawn.mapRect(1175, -1975, 250, 75);
// spawn.mapRect(200, -2150, 25, 250);
// spawn.mapRect(475, -2150, 25, 250);
//portal walls
// spawn.mapRect(575, -8, 100, 50);
// spawn.mapRect(925, -8, 100, 50);
// spawn.mapRect(675,t -625, 250, 675);
// spawn.mapRect(1700, 75, 150, 25);
// spawn.mapRect(1700, -700, 150, 25);
// spawn.mapRect(1850, 0, 525, 100);
// spawn.mapRect(1850, -700, 525, 100);
// spawn.bodyRect(1540, -1110, 300, 25, 0.9);
// spawn.boost(4150, 0, 1300);
// spawn.randomSmallMob(1300, -70);
// spawn.randomMob(2650, -975, 0.8);
// spawn.randomBoss(1700, -900, 0.4);
// if (game.difficulty > 3) spawn.randomLevelBoss(2200, -1300);
powerUps.addRerollToLevel() //needs to run after mobs are spawned
},
sewers() {
const rotor = level.rotor(5100, 2425, -0.001)
@@ -2356,4 +2455,161 @@ const level = {
World.add(engine.world, consBB[i]);
}
},
rotor(x, y, rotate = 0, radius = 900, width = 50, density = 0.0005) {
const rotor1 = Matter.Bodies.rectangle(x, y, width, radius, {
density: density,
isNotSticky: true,
isNotHoldable: true
});
const rotor2 = Matter.Bodies.rectangle(x, y, width, radius, {
angle: Math.PI / 2,
density: density,
isNotSticky: true,
isNotHoldable: true
});
rotor = Body.create({ //combine rotor1 and rotor2
parts: [rotor1, rotor2],
restitution: 0,
collisionFilter: {
category: cat.body,
mask: cat.body | cat.mob | cat.mobBullet | cat.mobShield | cat.powerUp | cat.player | cat.bullet
},
});
Matter.Body.setPosition(rotor, {
x: x,
y: y
});
World.add(engine.world, [rotor]);
body[body.length] = rotor1
body[body.length] = rotor2
setTimeout(function () {
rotor.collisionFilter.category = cat.body;
rotor.collisionFilter.mask = cat.body | cat.player | cat.bullet | cat.mob | cat.mobBullet //| cat.map
}, 1000);
const constraint = Constraint.create({ //fix rotor in place, but allow rotation
pointA: {
x: x,
y: y
},
bodyB: rotor
});
World.add(engine.world, constraint);
if (rotate) {
rotor.rotate = function () {
if (!mech.isBodiesAsleep) {
Matter.Body.applyForce(rotor, {
x: rotor.position.x + 100,
y: rotor.position.y + 100
}, {
x: rotate * rotor.mass,
y: 0
})
} else {
Matter.Body.setAngularVelocity(rotor, 0);
}
}
}
composite[composite.length] = rotor
return rotor
},
button(x, y, width = 66) {
spawn.mapVertex(x + 35, y + 2, "70 10 -70 10 -40 -10 40 -10");
map[map.length - 1].restitution = 0;
map[map.length - 1].friction = 1;
map[map.length - 1].frictionStatic = 1;
// const buttonSensor = Bodies.rectangle(x + 35, y - 1, 70, 20, {
// isSensor: true
// });
return {
isUp: false,
min: {
x: x + 2,
y: y - 11
},
max: {
x: x + width,
y: y - 10
},
width: width,
height: 20,
query() {
// if (Matter.Query.collides(buttonSensor, body).length === 0 && Matter.Query.collides(buttonSensor, [player]).length === 0) {
if (Matter.Query.region(body, this).length === 0 && Matter.Query.region([player], this).length === 0) {
this.isUp = true;
} else {
this.isUp = false;
// const list = Matter.Query.collides(buttonSensor, body)
// if (list.length > 0) {
// Matter.Body.setVelocity(list[0].bodyB, {
// x: 0,
// y: 0
// });
// }
}
},
draw() {
ctx.fillStyle = "hsl(0, 100%, 70%)"
if (this.isUp) {
ctx.fillRect(this.min.x, this.min.y - 10, this.width, 20)
} else {
ctx.fillRect(this.min.x, this.min.y, this.width, 25)
}
//draw sensor zone
// ctx.beginPath();
// sensor = buttonSensor.vertices;
// ctx.moveTo(sensor[0].x, sensor[0].y);
// for (let i = 1; i < sensor.length; ++i) {
// ctx.lineTo(sensor[i].x, sensor[i].y);
// }
// ctx.lineTo(sensor[0].x, sensor[0].y);
// ctx.fillStyle = "rgba(255, 255, 0, 0.3)";
// ctx.fill();
}
}
},
hazard(x, y, width, height, damage = 0.0005, color = "hsl(160, 100%, 35%)") {
return {
min: {
x: x,
y: y
},
max: {
x: x + width,
y: y + height
},
width: width,
height: height,
maxHeight: height,
query() {
if (this.height > 0 && Matter.Query.region([player], this).length && !mech.isStealth) {
mech.damage(damage)
const drain = 0.005
if (mech.energy > drain) mech.energy -= drain
}
},
draw() {
ctx.fillStyle = color
ctx.fillRect(this.min.x, this.min.y, this.width, this.height)
},
level(isFill) {
const growSpeed = 1
if (isFill) {
if (this.height < this.maxHeight) {
this.height += growSpeed
this.min.y -= growSpeed
this.max.y = this.min.y + this.height
}
} else if (this.height > 0) {
this.height -= growSpeed
this.min.y += growSpeed
this.max.y = this.min.y + this.height
}
}
}
},
};

View File

@@ -643,7 +643,7 @@ const mod = {
maxCount: 1,
count: 0,
allowed() {
return game.fpsCapDefault > 45
return game.fpsCapDefault > 45 && !mod.isRailTimeSlow
},
requires: "FPS above 45",
effect() {
@@ -852,22 +852,6 @@ const mod = {
mech.displayHealth();
}
},
{
name: "negentropy",
description: "at the start of each <strong>level</strong><br><strong class='color-h'>heal</strong> up to <strong>66%</strong> of <strong>maximum health</strong>",
maxCount: 1,
count: 0,
allowed() {
return mech.maxHealth > 1 || mod.isArmorFromPowerUps
},
requires: "increased max health",
effect() {
mod.isHealLowHealth = true;
},
remove() {
mod.isHealLowHealth = false;
}
},
{
name: "crystallized armor",
description: "increase <strong>maximum</strong> <strong class='color-h'>health</strong> by <strong>5%</strong> for each<br>unused <strong>power up</strong> at the end of a <strong>level</strong>",
@@ -884,6 +868,38 @@ const mod = {
mod.isArmorFromPowerUps = false;
}
},
{
name: "negentropy",
description: "at the start of each <strong>level</strong><br><strong class='color-h'>heal</strong> up to <strong>66%</strong> of <strong>maximum health</strong>",
maxCount: 1,
count: 0,
allowed() {
return mech.maxHealth > 1 || mod.isArmorFromPowerUps
},
requires: "increased max health",
effect() {
mod.isHealLowHealth = true;
},
remove() {
mod.isHealLowHealth = false;
}
},
// {
// name: "prismatic cleavage",
// description: "harm that would be fatal no longer kills you<br>instead it is removed from your maximum health",
// maxCount: 1,
// count: 0,
// allowed() {
// return mech.maxHealth > 1 || mod.isArmorFromPowerUps
// },
// requires: "increased max health",
// effect() {
// mod.isMaxHealthRemove = true;
// },
// remove() {
// mod.isMaxHealthRemove = false;
// }
// },
{
name: "recursive healing",
description: "<strong class='color-h'>healing</strong> <strong>power ups</strong> trigger <strong>1</strong> more time",
@@ -1245,6 +1261,22 @@ const mod = {
mod.bulletSize = 1;
}
},
{
name: "high caliber",
description: "<strong>100%</strong> increased <strong>minigun</strong> bullet size<br><strong>100%</strong> increased <strong>delay</strong> after firing",
maxCount: 1,
count: 0,
allowed() {
return mod.haveGunCheck("minigun")
},
requires: "minigun",
effect() {
mod.highCaliber = 2
},
remove() {
mod.highCaliber = 1
}
},
{
name: "ice crystal nucleation",
description: "your <strong>minigun</strong> uses <strong class='color-f'>energy</strong> to condense<br>unlimited <strong class='color-s'>freezing</strong> <strong>bullets</strong> from water vapor",
@@ -1813,7 +1845,22 @@ const mod = {
mod.isFoamGrowOnDeath = false;
}
},
{
name: "frame-dragging",
description: "<strong>slow time</strong> while charging the <strong>rail gun</strong><br>charging no longer drains <strong class='color-f'>energy</strong>",
maxCount: 1,
count: 0,
allowed() {
return game.fpsCapDefault > 45 && mod.haveGunCheck("rail gun") && !mod.isSlowFPS
},
requires: "rail gun && FPS above 45",
effect() {
mod.isRailTimeSlow = true;
},
remove() {
mod.isRailTimeSlow = false;
}
},
{
name: "fragmenting projectiles",
description: "<strong>rail gun</strong> fragments into <strong>nails</strong><br>after hitting mobs at high speeds",
@@ -2384,5 +2431,7 @@ const mod = {
isRerollHaste: null,
rerollHaste: null,
isMineDrop: null,
isRerollBots: null
isRerollBots: null,
isRailTimeSlow: null
// isMaxHealthRemove: null
}

View File

@@ -945,14 +945,7 @@ const mech = {
y: powerUp[i].velocity.y * 0.11
});
if (dist2 < 5000 && !game.isChoosing) { //use power up if it is close enough
if (mod.isMassEnergy) mech.energy = mech.maxEnergy * 3;
if (mod.isMineDrop) b.mine({
x: mech.pos.x,
y: mech.pos.y
}, {
x: 0,
y: 0
}, 0, mod.isMineAmmoBack)
powerUps.onPickUp();
Matter.Body.setVelocity(player, { //player knock back, after grabbing power up
x: player.velocity.x + ((powerUp[i].velocity.x * powerUp[i].mass) / player.mass) * 0.3,
y: player.velocity.y + ((powerUp[i].velocity.y * powerUp[i].mass) / player.mass) * 0.3
@@ -1663,7 +1656,7 @@ const mech = {
mech.grabPowerUp();
mech.lookForPickUp(180);
const DRAIN = 0.0017
const DRAIN = 0.0014
if (mech.energy > DRAIN) {
mech.energy -= DRAIN;
if (mech.energy < DRAIN) {

View File

@@ -195,7 +195,9 @@ const powerUps = {
let choice2 = -1
let choice3 = -1
if (choice1 > -1) {
let text = `<div class='cancel' onclick='powerUps.endDraft()'>✕</div><h3 style = 'color:#fff; text-align:left; margin: 0px;'>choose a field</h3>`
let text = ""
if (!mod.isDeterminism) text += `<div class='cancel' onclick='powerUps.endDraft()'>✕</div>`
text += `<h3 style = 'color:#fff; text-align:left; margin: 0px;'>choose a field</h3>`
text += `<div class="choose-grid-module" onclick="powerUps.choose('field',${choice1})"><div class="grid-title"><div class="circle-grid field"></div> &nbsp; ${mech.fieldUpgrades[choice1].name}</div> ${mech.fieldUpgrades[choice1].description}</div>`
if (!mod.isDeterminism) {
choice2 = pick(mech.fieldUpgrades, choice1)
@@ -263,7 +265,9 @@ const powerUps = {
}
}
let text = `<div class='cancel' onclick='powerUps.endDraft()'>✕</div><h3 style = 'color:#fff; text-align:left; margin: 0px;'>choose a mod</h3>`
let text = ""
if (!mod.isDeterminism) text += `<div class='cancel' onclick='powerUps.endDraft()'>✕</div>`
text += `<h3 style = 'color:#fff; text-align:left; margin: 0px;'>choose a mod</h3>`
let choice1 = pick()
let choice2 = -1
let choice3 = -1
@@ -333,7 +337,9 @@ const powerUps = {
let choice2 = -1
let choice3 = -1
if (choice1 > -1) {
let text = `<div class='cancel' onclick='powerUps.endDraft()'>✕</div><h3 style = 'color:#fff; text-align:left; margin: 0px;'>choose a gun</h3>`
let text = ""
if (!mod.isDeterminism) text += `<div class='cancel' onclick='powerUps.endDraft()'>✕</div>`
text += `<h3 style = 'color:#fff; text-align:left; margin: 0px;'>choose a gun</h3>`
text += `<div class="choose-grid-module" onclick="powerUps.choose('gun',${choice1})"><div class="grid-title"><div class="circle-grid gun"></div> &nbsp; ${b.guns[choice1].name}</div> ${b.guns[choice1].description}</div>`
if (!mod.isDeterminism) {
choice2 = pick(b.guns, choice1)
@@ -365,6 +371,16 @@ const powerUps = {
}
}
},
onPickUp() {
if (mod.isMassEnergy) mech.energy = mech.maxEnergy * 3;
if (mod.isMineDrop) b.mine({
x: mech.pos.x,
y: mech.pos.y
}, {
x: 0,
y: 0
}, 0, mod.isMineAmmoBack)
},
giveRandomAmmo() {
const ammoTarget = Math.floor(Math.random() * (b.guns.length));
const ammo = Math.ceil(b.guns[ammoTarget].ammoPack * 6);

View File

@@ -1,8 +1,18 @@
determinism mod no longer lets you cancel power ups
rerolls now spawn at about 1 per level
mod: frame dragging - rail gun doesn't drain energy, and slows time while charging
mod: high caliber - minigun bullets are bigger, but fire slower
************** TODO - n-gon **************
using a reroll gives you, a heal or ammo
level boss: boss that dies and comes back to life but with one less side until it hits 3 sides
change color too (hsl)
boss shrinks and moves faster after each death
mechanic: lose max health instead of taking fatal damage
map: laboratory
rooms with switches that change physics
gravity room
@@ -10,10 +20,17 @@ map: laboratory
laser room
radiation room
map: observatory
button controls rotation of telescope
laser beam shoots out of telescope
button opens the dome
map: prison
doors linked to buttons
mobs inside the doors?
map: airport
button: blocks that are on the button at an angle will slowly slide off the button
maybe just avoid long blocks near the button?
maybe actively hold the button in place?
@@ -42,12 +59,6 @@ field that pushes blocks and mobs away
mod - AoE radiation might work when the effect ends
or maybe just anytime another mob is near
medium caliber gun in between minigun and rail gun
mod: electricity damages mobs that get near the bullet
get ammo back if it hits mobs
ammo returns to you if it misses
bullets have a gentle arc?
mob that flashes the player (makes the graphics not update for a couple seconds)
mod - do 50% more damage in close, but 50% less at a distance