sticky mines

mines are sticky
some mods trigger effects on pickup
This commit is contained in:
landgreen
2020-01-11 08:48:40 -08:00
parent 9c2433d50d
commit 7068a48903
9 changed files with 428 additions and 247 deletions

View File

@@ -27,7 +27,8 @@ const b = {
isModEntanglement: null, isModEntanglement: null,
isModMassEnergy: null, isModMassEnergy: null,
isModFourOptions: null, isModFourOptions: null,
modGuardianCount: null, modLaserBotCount: null,
modNailBotCount: null,
modCollisionImmuneCycles: null, modCollisionImmuneCycles: null,
modBlockDmg: null, modBlockDmg: null,
modPiezo: null, modPiezo: null,
@@ -55,7 +56,8 @@ const b = {
b.isModFarAwayDmg = false; b.isModFarAwayDmg = false;
b.isModEntanglement = false; b.isModEntanglement = false;
b.isModMassEnergy = false; b.isModMassEnergy = false;
b.modGuardianCount = 0; b.modLaserBotCount = 0;
b.modNailBotCount = 0;
b.modCollisionImmuneCycles = 30; b.modCollisionImmuneCycles = 30;
b.modBlockDmg = 0; b.modBlockDmg = 0;
b.modPiezo = 0; b.modPiezo = 0;
@@ -97,11 +99,29 @@ const b = {
}, },
{ {
name: "kinetic bombardment", //3 name: "kinetic bombardment", //3
description: "do extra <strong class='color-d'>damage</strong> from a distance<br><em>up to 50% increase at about 30 steps away</em>", description: "do up to 33% more <strong class='color-d'>damage</strong> at a distance<br><em>increase starts at about 6 steps away</em>",
maxCount: 1, maxCount: 1,
count: 0, count: 0,
effect() { effect() {
b.isModFarAwayDmg = true; //used in mob.damage() b.isModFarAwayDmg = true; //used in mob.damage()
game.drawList.push({ //draw range
//add dmg to draw queue
x: player.position.x,
y: player.position.y,
radius: 3000,
color: "rgba(255,0,0,0.05)",
time: 120
});
game.drawList.push({ //draw range
//add dmg to draw queue
x: player.position.x,
y: player.position.y,
radius: 500,
color: "rgba(0,0,0,0.2)",
time: 120
});
} }
}, },
{ {
@@ -113,6 +133,16 @@ const b = {
b.isModLowHealthDmg = true; //used in mob.damage() b.isModLowHealthDmg = true; //used in mob.damage()
} }
}, },
{
name: "high explosives", //15
description: "the radius of <strong class='color-e'>explosions</strong> are +20% <strong>larger</strong><br>immune to <strong>harm</strong> from <strong class='color-e'>explosions</strong>",
maxCount: 4,
count: 0,
effect: () => {
b.modExplosionRadius += 0.2;
b.isModImmuneExplosion = true;
}
},
{ {
name: "auto-loading heuristics", //5 name: "auto-loading heuristics", //5
description: "your <strong>delay</strong> after firing is +12% <strong>shorter</strong>", description: "your <strong>delay</strong> after firing is +12% <strong>shorter</strong>",
@@ -147,6 +177,29 @@ const b = {
count: 0, count: 0,
effect() { effect() {
b.modSpores += 0.11; b.modSpores += 0.11;
for (let i = 0; i < 10; i++) {
b.spore(player) //spawn drone
}
}
},
{
name: "laser-bot", //10
description: "a bot <strong>protects</strong> the space around you<br>uses a <strong>short range</strong> laser that drains <strong class='color-f'>energy</strong>",
maxCount: 4,
count: 0,
effect() {
b.modLaserBotCount++;
b.guardian();
}
},
{
name: "nail-bot", //11
description: "a bot <strong>protects</strong> the space around you<br>fires a <strong>nail</strong> at targets in range",
maxCount: 4,
count: 0,
effect() {
b.modNailBotCount++;
b.nailBot();
} }
}, },
{ {
@@ -156,29 +209,13 @@ const b = {
count: 0, count: 0,
effect() { effect() {
b.isModDroneOnDamage = true; b.isModDroneOnDamage = true;
for (let i = 0; i < 3; i++) {
b.drone() //spawn drone
}
} }
}, },
{ {
name: "guardian", //10 name: "bremsstrahlung radiation", //13
description: "a bot <strong>protects</strong> the space around you<br>uses a <strong>short range</strong> laser that drains <strong class='color-f'>energy</strong>",
maxCount: 4,
count: 0,
effect() {
b.modGuardianCount++;
b.guardian();
}
},
{
name: "Pauli exclusion", //11
description: "unable to <strong>collide</strong> with enemies for +2 seconds<br>activates after being <strong>harmed</strong> from a collision",
maxCount: 1,
count: 0,
effect() {
b.modCollisionImmuneCycles += 120;
}
},
{
name: "bremsstrahlung radiation", //12
description: "when your <strong>field blocks</strong> it also does <strong class='color-d'>damage</strong>", description: "when your <strong>field blocks</strong> it also does <strong class='color-d'>damage</strong>",
maxCount: 4, maxCount: 4,
count: 0, count: 0,
@@ -187,27 +224,8 @@ const b = {
} }
}, },
{ {
name: "annihilation", //13 name: "entanglement", //16
description: "after <strong>touching</strong> enemies, they are annihilated", description: "using your first gun reduces <strong>harm</strong><br>scales by <strong>10%</strong> for each gun in your inventory",
maxCount: 1,
count: 0,
effect() {
b.isModAnnihilation = true
}
},
{
name: "high explosives", //14
description: "the radius of <strong class='color-e'>explosions</strong> are +20% <strong>larger</strong><br>immune to <strong>harm</strong> from <strong class='color-e'>explosions</strong>",
maxCount: 4,
count: 0,
effect: () => {
b.modExplosionRadius += 0.2;
b.isModImmuneExplosion = true;
}
},
{
name: "entanglement", //15
description: "using your first gun reduces <strong>harm</strong><br>scales by <strong>7%</strong> for each gun in your inventory",
maxCount: 1, maxCount: 1,
count: 0, count: 0,
effect() { effect() {
@@ -215,88 +233,7 @@ const b = {
} }
}, },
{ {
name: "piezoelectricity", //16 name: "squirrel-cage rotor", //27
description: "gain <strong class='color-f'>energy</strong> proportional to <strong>harm</strong> received",
maxCount: 4,
count: 0,
effect() {
b.modPiezo += 2
}
},
{
name: "energy conservation", //17
description: "gain <strong class='color-f'>energy</strong> proportional to <strong class='color-d'>damage</strong> done",
maxCount: 4,
count: 0,
effect() {
b.modEnergySiphon += 0.18;
}
},
{
name: "entropy exchange", //18
description: "<strong class='color-h'>heal</strong> proportional to <strong class='color-d'>damage</strong> done",
maxCount: 4,
count: 0,
effect() {
b.modHealthDrain += 0.015;
}
},
{
name: "overcharge", //19
description: "charge <strong class='color-f'>energy</strong> <strong>+33%</strong> beyond your <strong>maximum</strong>",
maxCount: 4,
count: 0,
effect() {
mech.fieldEnergyMax += 0.33
}
},
{
name: "supersaturation", //20
description: "<strong class='color-h'>heal</strong> <strong>+33%</strong> beyond your <strong>max health</strong>",
maxCount: 4,
count: 0,
effect() {
mech.maxHealth += 0.33
}
},
{
name: "recursive healing", //21
description: "<strong class='color-h'>healing</strong> power ups trigger an extra time.",
maxCount: 4,
count: 0,
effect() {
b.modRecursiveHealing += 1
}
},
{
name: "mass-energy equivalence", //22
description: "convert the mass of <strong>power ups</strong> into <strong class='color-f'>energy</strong><br>power ups fill your <strong class='color-f'>energy</strong> and <strong class='color-h'>heal</strong> for +5%",
maxCount: 1,
count: 0,
effect: () => {
b.isModMassEnergy = true // used in mech.usePowerUp
}
},
{
name: "+1 cardinality", //23
description: "one extra <strong>choice</strong> when selecting <strong>power ups</strong>",
maxCount: 1,
count: 0,
effect: () => {
b.isModFourOptions = true;
}
},
{
name: "Bayesian inference", //24
description: "<strong>20%</strong> chance for double <strong>power ups</strong> to drop<br>one fewer <strong>choice</strong> when selecting <strong>power ups</strong>",
maxCount: 1,
count: 0,
effect: () => {
b.isModBayesian = 0.20;
}
},
{
name: "squirrel-cage rotor", //25
description: "<strong>jump</strong> higher and <strong>move</strong> faster<br>reduced <strong>harm</strong> from <strong>falling</strong> ", description: "<strong>jump</strong> higher and <strong>move</strong> faster<br>reduced <strong>harm</strong> from <strong>falling</strong> ",
maxCount: 1, maxCount: 1,
count: 0, count: 0,
@@ -307,8 +244,124 @@ const b = {
} }
}, },
{ {
name: "quantum immortality", //26 name: "Pauli exclusion", //12
description: "after <strong>dying</strong>, continue in an <strong>alternate reality</strong><br><em>guns, ammo, and field are randomized</em>", description: "unable to <strong>collide</strong> with enemies for +2 seconds<br>activates after being <strong>harmed</strong> from a collision",
maxCount: 1,
count: 0,
effect() {
b.modCollisionImmuneCycles += 120;
mech.collisionImmune = mech.cycle + b.modCollisionImmuneCycles; //player is immune to collision damage for 30 cycles
}
},
{
name: "annihilation", //14
description: "after <strong>touching</strong> enemies, they are annihilated",
maxCount: 1,
count: 0,
effect() {
b.isModAnnihilation = true
}
},
{
name: "piezoelectricity", //17
description: "after <strong>colliding</strong> with enemies gain 50% <strong class='color-f'>energy</strong>",
maxCount: 1,
count: 0,
effect() {
b.modPiezo = 0.50
}
},
{
name: "energy conservation", //18
description: "gain <strong class='color-f'>energy</strong> proportional to <strong class='color-d'>damage</strong> done",
maxCount: 4,
count: 0,
effect() {
b.modEnergySiphon += 0.18;
mech.fieldMeter = mech.fieldEnergyMax
}
},
{
name: "entropy exchange", //19
description: "<strong class='color-h'>heal</strong> proportional to <strong class='color-d'>damage</strong> done",
maxCount: 4,
count: 0,
effect() {
b.modHealthDrain += 0.015;
}
},
{
name: "overcharge", //20
description: "charge <strong class='color-f'>energy</strong> <strong>+33%</strong> beyond your <strong>maximum</strong>",
maxCount: 4,
count: 0,
effect() {
mech.fieldEnergyMax += 0.33
mech.fieldMeter += 0.33
}
},
{
name: "supersaturation", //21
description: "<strong class='color-h'>heal</strong> <strong>+33%</strong> beyond your <strong>max health</strong>",
maxCount: 4,
count: 0,
effect() {
mech.maxHealth += 0.33
mech.addHealth(0.33)
}
},
{
name: "recursive healing", //22
description: "<strong class='color-h'>healing</strong> power ups trigger an extra time.",
maxCount: 4,
count: 0,
effect() {
b.modRecursiveHealing += 1
}
},
{
name: "mass-energy equivalence", //23
description: "convert the mass of <strong>power ups</strong> into <strong class='color-f'>energy</strong><br>power ups fill your <strong class='color-f'>energy</strong> and <strong class='color-h'>heal</strong> for +5%",
maxCount: 1,
count: 0,
effect: () => {
b.isModMassEnergy = true // used in mech.usePowerUp
mech.fieldMeter = mech.fieldEnergyMax
}
},
{
name: "+1 cardinality", //24
description: "one extra <strong>choice</strong> when selecting <strong>power ups</strong>",
maxCount: 1,
count: 0,
effect: () => {
b.isModFourOptions = true;
}
},
{
name: "Bayesian inference", //25
description: "<strong>20%</strong> chance for double <strong>power ups</strong> to drop<br>one fewer <strong>choice</strong> when selecting <strong>power ups</strong>",
maxCount: 1,
count: 0,
effect: () => {
b.isModBayesian = 0.20;
}
},
{
name: "Born rule", //26
description: "<strong>remove</strong> all current <strong class='color-m'>mods</strong><br>spawn new <strong class='color-m'>mods</strong> to replace them",
maxCount: 1,
count: 0,
effect: () => {
for (let i = 0; i < b.modCount; i++) { // spawn new mods
powerUps.spawn(mech.pos.x, mech.pos.y, "mod");
}
b.setModDefaults(); // remove all mods
}
},
{
name: "quantum immortality", //28
description: "after <strong>dying</strong>, continue in an <strong>alternate reality</strong><br><em>guns, ammo, field, and mods are randomized</em>",
maxCount: 1, maxCount: 1,
count: 0, count: 0,
effect() { effect() {
@@ -461,6 +514,21 @@ const b = {
} }
} }
}, },
onCollision(event) {
const pairs = event.pairs;
for (let i = 0, j = pairs.length; i != j; i++) {
//map + bullet collisions
if (pairs[i].bodyA.collisionFilter.category === cat.map && pairs[i].bodyB.collisionFilter.category === cat.bullet) {
collideBulletStatic(pairs[i].bodyB)
} else if (pairs[i].bodyB.collisionFilter.category === cat.map && pairs[i].bodyA.collisionFilter.category === cat.bullet) {
collideBulletStatic(pairs[i].bodyA)
}
function collideBulletStatic(obj) {
if (obj.onWallHit) obj.onWallHit();
}
}
},
explosion(where, radius) { explosion(where, radius) {
radius *= b.modExplosionRadius radius *= b.modExplosionRadius
// typically explode is used for some bullets with .onEnd // typically explode is used for some bullets with .onEnd
@@ -718,7 +786,7 @@ const b = {
const THRUST = 0.0015 const THRUST = 0.0015
const dir = mech.angle + 0.2 * (Math.random() - 0.5); const dir = mech.angle + 0.2 * (Math.random() - 0.5);
const RADIUS = (4.5 + 3 * Math.random()) * b.modBulletSize const RADIUS = (4.5 + 3 * Math.random()) * b.modBulletSize
bullet[me] = Bodies.circle(mech.pos.x + 30 * Math.cos(mech.angle), mech.pos.y + 30 * Math.sin(mech.angle), RADIUS, { bullet[me] = Bodies.polygon(mech.pos.x + 30 * Math.cos(mech.angle), mech.pos.y + 30 * Math.sin(mech.angle), 8, RADIUS, {
angle: dir, angle: dir,
inertia: Infinity, inertia: Infinity,
friction: 0.05, friction: 0.05,
@@ -813,6 +881,75 @@ const b = {
y: speed * Math.sin(dir) y: speed * Math.sin(dir)
}); });
}, },
nail(pos, velocity, dmg = 0) {
const me = bullet.length;
bullet[me] = Bodies.rectangle(pos.x, pos.y, 25 * b.modBulletSize, 2 * b.modBulletSize, b.fireAttributes(Math.atan2(velocity.y, velocity.x)));
Matter.Body.setVelocity(bullet[me], velocity);
World.add(engine.world, bullet[me]); //add bullet to world
bullet[me].endCycle = game.cycle + 60 + 18 * Math.random();
bullet[me].dmg = dmg
bullet[me].do = function () {};
},
nailBot(speed = 1) {
const me = bullet.length;
const dir = mech.angle;
const RADIUS = (10 + 5 * Math.random()) * b.modBulletSize
bullet[me] = Bodies.polygon(mech.pos.x + 30 * Math.cos(mech.angle), mech.pos.y + 30 * Math.sin(mech.angle), 4, RADIUS, {
angle: dir,
friction: 0,
frictionStatic: 0,
restitution: 0.4 + 0.5 * Math.random(),
dmg: 0, // 0.14 //damage done in addition to the damage from momentum
minDmgSpeed: 2,
lookFrequency: 45 + Math.floor(17 * Math.random()),
acceleration: 0.0025 + 0.001 * Math.random(),
range: 300 + Math.floor(70 * Math.random()),
endCycle: Infinity,
classType: "bullet",
collisionFilter: {
category: cat.bullet,
mask: cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet | cat.mobShield
},
lockedOn: null,
onDmg() {
this.lockedOn = null
},
onEnd() {},
do() {
if (!(game.cycle % this.lookFrequency)) {
let target
for (let i = 0, len = mob.length; i < len; i++) {
const dist = Vector.magnitudeSquared(Vector.sub(this.position, mob[i].position));
if (dist < 2000000 && //1400*1400
Matter.Query.ray(map, this.position, mob[i].position).length === 0 &&
Matter.Query.ray(body, this.position, mob[i].position).length === 0) {
target = Vector.add(mob[i].position, Vector.mult(mob[i].velocity, Math.sqrt(dist) / 60))
const SPEED = 50
b.nail(this.position, Vector.mult(Vector.normalise(Vector.sub(target, this.position)), SPEED), 0.5)
break;
}
}
}
const distanceToPlayer = Vector.magnitude(Vector.sub(this.position, mech.pos))
if (distanceToPlayer > this.range * 0.2) { //if far away move towards player
this.force = Vector.mult(Vector.normalise(Vector.sub(mech.pos, this.position)), this.mass * this.acceleration)
this.frictionAir = 0.04
} else { //close to player
this.frictionAir = 0.005
//add player's velocity
Matter.Body.setVelocity(this, Vector.add(Vector.mult(this.velocity, 1), Vector.mult(player.velocity, 0.02)));
}
}
})
World.add(engine.world, bullet[me]); //add bullet to world
Matter.Body.setVelocity(bullet[me], {
x: speed * Math.cos(dir),
y: speed * Math.sin(dir)
});
},
guardian(speed = 1) { guardian(speed = 1) {
const me = bullet.length; const me = bullet.length;
const dir = mech.angle; const dir = mech.angle;
@@ -920,7 +1057,9 @@ const b = {
gun = options[Math.floor(Math.random() * options.length)] gun = options[Math.floor(Math.random() * options.length)]
} }
if (gun === "all") { if (gun === "all") {
if (b.guns[b.activeGun].switchOff) b.guns[b.activeGun].switchOff(); //run code when switching away from a gun
b.activeGun = 0; b.activeGun = 0;
if (b.guns[b.activeGun].switchOn) b.guns[b.activeGun].switchOn(); //run code when switching to a new gun
b.inventoryGun = 0; b.inventoryGun = 0;
for (let i = 0; i < b.guns.length; i++) { for (let i = 0; i < b.guns.length; i++) {
b.inventory[i] = i; b.inventory[i] = i;
@@ -930,6 +1069,7 @@ const b = {
} else { } else {
if (!b.guns[gun].have) b.inventory.push(gun); if (!b.guns[gun].have) b.inventory.push(gun);
if (b.activeGun === null) b.activeGun = gun //if no active gun switch to new gun if (b.activeGun === null) b.activeGun = gun //if no active gun switch to new gun
if (b.guns[b.activeGun].switchOn) b.guns[b.activeGun].switchOn(); //run code when switching to a new gun
b.guns[gun].have = true; b.guns[gun].have = true;
b.guns[gun].ammo = b.guns[gun].ammoPack * ammoPacks; b.guns[gun].ammo = b.guns[gun].ammoPack * ammoPacks;
} }
@@ -1009,7 +1149,7 @@ const b = {
let dir = mech.angle - SPREAD * 2; let dir = mech.angle - SPREAD * 2;
for (let i = 0; i < 5; i++) { for (let i = 0; i < 5; i++) {
const me = bullet.length; const me = bullet.length;
bullet[me] = Bodies.circle(mech.pos.x + 30 * Math.cos(mech.angle), mech.pos.y + 30 * Math.sin(mech.angle), 7 * b.modBulletSize, b.fireAttributes(dir, false)); bullet[me] = Bodies.polygon(mech.pos.x + 30 * Math.cos(mech.angle), mech.pos.y + 30 * Math.sin(mech.angle), 10, 7 * b.modBulletSize, b.fireAttributes(dir, false));
World.add(engine.world, bullet[me]); //add bullet to world World.add(engine.world, bullet[me]); //add bullet to world
Matter.Body.setVelocity(bullet[me], { Matter.Body.setVelocity(bullet[me], {
x: SPEED * Math.cos(dir), x: SPEED * Math.cos(dir),
@@ -1077,7 +1217,7 @@ const b = {
const dir = mech.angle const dir = mech.angle
const SCALE = (mech.crouch ? 0.963 : 0.95) const SCALE = (mech.crouch ? 0.963 : 0.95)
const wiggleMag = ((mech.crouch) ? 0.004 : 0.005) * ((mech.flipLegs === 1) ? 1 : -1) const wiggleMag = ((mech.crouch) ? 0.004 : 0.005) * ((mech.flipLegs === 1) ? 1 : -1)
bullet[me] = Bodies.circle(mech.pos.x + 25 * Math.cos(dir), mech.pos.y + 25 * Math.sin(dir), 10 * b.modBulletSize, { bullet[me] = Bodies.polygon(mech.pos.x + 25 * Math.cos(dir), mech.pos.y + 25 * Math.sin(dir), 10, 10 * b.modBulletSize, {
angle: dir, angle: dir,
cycle: -0.43, //adjust this number until the bullets line up with the cross hairs cycle: -0.43, //adjust this number until the bullets line up with the cross hairs
endCycle: game.cycle + Math.floor((mech.crouch ? 155 : 120) * b.isModBulletsLastLonger), endCycle: game.cycle + Math.floor((mech.crouch ? 155 : 120) * b.isModBulletsLastLonger),
@@ -1461,19 +1601,19 @@ const b = {
name: "grenades", //8 name: "grenades", //8
description: "lob a single bouncy projectile<br><strong class='color-e'>explodes</strong> on contact or after one second", description: "lob a single bouncy projectile<br><strong class='color-e'>explodes</strong> on contact or after one second",
ammo: 0, ammo: 0,
ammoPack: 4, ammoPack: 6,
have: false, have: false,
isStarterGun: false, isStarterGun: false,
fire() { fire() {
const me = bullet.length; const me = bullet.length;
const dir = mech.angle; // + Math.random() * 0.05; const dir = mech.angle; // + Math.random() * 0.05;
bullet[me] = Bodies.circle(mech.pos.x + 30 * Math.cos(mech.angle), mech.pos.y + 30 * Math.sin(mech.angle), 20 * b.modBulletSize, b.fireAttributes(dir, false)); bullet[me] = Bodies.circle(mech.pos.x + 30 * Math.cos(mech.angle), mech.pos.y + 30 * Math.sin(mech.angle), 20 * b.modBulletSize, b.fireAttributes(dir, true));
b.fireProps(mech.crouch ? 30 : 20, mech.crouch ? 43 : 32, dir, me); //cd , speed b.fireProps(mech.crouch ? 30 : 20, mech.crouch ? 43 : 32, dir, me); //cd , speed
Matter.Body.setDensity(bullet[me], 0.0005); Matter.Body.setDensity(bullet[me], 0.0005);
bullet[me].totalCycles = 100; bullet[me].totalCycles = 100;
bullet[me].endCycle = game.cycle + Math.floor(mech.crouch ? 120 : 80); bullet[me].endCycle = game.cycle + Math.floor(mech.crouch ? 120 : 80);
bullet[me].restitution = 0.5; bullet[me].restitution = 0.2;
bullet[me].explodeRad = 310; bullet[me].explodeRad = 275;
bullet[me].onEnd = b.explode; //makes bullet do explosive damage before despawn bullet[me].onEnd = b.explode; //makes bullet do explosive damage before despawn
bullet[me].minDmgSpeed = 1; bullet[me].minDmgSpeed = 1;
bullet[me].onDmg = function () { bullet[me].onDmg = function () {
@@ -1595,17 +1735,18 @@ const b = {
} }
}, { }, {
name: "mine", //10 name: "mine", //10
description: "drop a proximity <strong>mine</strong> that ejects nails<br><em>arms after being still for 1 second</em>", description: "drop a <strong>proximity</strong> mine that <strong>sticks</strong> to walls<br>fires <strong>nails</strong> at enemies within range",
ammo: 0, ammo: 0,
ammoPack: 8, ammoPack: 6,
have: false, have: false,
isStarterGun: false, isStarterGun: false,
fire() { fire() {
const me = bullet.length; const me = bullet.length;
const dir = mech.angle; const dir = mech.angle;
bullet[me] = Bodies.rectangle(mech.pos.x + 30 * Math.cos(mech.angle), mech.pos.y + 30 * Math.sin(mech.angle), 45 * b.modBulletSize, 16 * b.modBulletSize, { if (mech.crouch) {
bullet[me] = Bodies.rectangle(mech.pos.x + 35 * Math.cos(mech.angle), mech.pos.y + 35 * Math.sin(mech.angle), 45 * b.modBulletSize, 16 * b.modBulletSize, {
angle: 0, angle: 0,
friction: 0.3, friction: 1,
frictionAir: 0, frictionAir: 0,
dmg: 0, //damage done in addition to the damage from momentum dmg: 0, //damage done in addition to the damage from momentum
classType: "bullet", classType: "bullet",
@@ -1617,65 +1758,87 @@ const b = {
onDmg() {}, onDmg() {},
onEnd() {} onEnd() {}
}); });
b.fireProps(mech.crouch ? 40 : 20, mech.crouch ? 24 : 7, dir, me); //cd , speed mech.fireCDcycle = mech.cycle + Math.floor(35 * b.modFireRate); // cool down
Matter.Body.setVelocity(bullet[me], {
x: mech.Vx / 2 + 26 * Math.cos(dir),
y: mech.Vy / 2 + 26 * Math.sin(dir)
});
bullet[me].torque += bullet[me].inertia * 0.0001 * (0.5 - Math.random()) bullet[me].torque += bullet[me].inertia * 0.0001 * (0.5 - Math.random())
bullet[me].endCycle = game.cycle + 1800 + 360 * Math.random(); } else {
bullet[me].cycle = 0 bullet[me] = Bodies.rectangle(mech.pos.x, mech.pos.y + 25, 45 * b.modBulletSize, 16 * b.modBulletSize, {
bullet[me].restitution = 0; angle: 0,
bullet[me].lookFrequency = 37 + Math.floor(37 * Math.random()) friction: 1,
bullet[me].range = 700 frictionAir: 0,
bullet[me].do = function () { dmg: 0, //damage done in addition to the damage from momentum
this.force.y += this.mass * 0.002; //extra gravity classType: "bullet",
collisionFilter: {
ctx.beginPath(); //draw block as grey category: cat.bullet,
ctx.moveTo(this.vertices[0].x, this.vertices[0].y); mask: cat.map | cat.body | cat.mob | cat.mobBullet | cat.mobShield | cat.bullet
for (let j = 1; j < this.vertices.length; j += 1) { },
ctx.lineTo(this.vertices[j].x, this.vertices[j].y); minDmgSpeed: 5,
onDmg() {},
onEnd() {}
});
mech.fireCDcycle = mech.cycle + Math.floor(20 * b.modFireRate); // cool down
Matter.Body.setVelocity(bullet[me], {
x: mech.Vx,
y: mech.Vy
});
} }
ctx.lineTo(this.vertices[0].x, this.vertices[0].y); World.add(engine.world, bullet[me]); //add bullet to world
ctx.fillStyle = "#457"; bullet[me].endCycle = game.cycle + 1800 + 360 * Math.random();
ctx.fill(); bullet[me].seeFrom = null;
bullet[me].restitution = 0;
if (this.speed < 1 && !mech.isBodiesAsleep) this.cycle++ bullet[me].lookFrequency = 41 + Math.floor(23 * Math.random())
if (this.cycle > 40) { bullet[me].range = 700
this.do = function () { bullet[me].arm = function () {
this.do = function () { //overwrite the do method for this bullet
this.force.y += this.mass * 0.002; //extra gravity this.force.y += this.mass * 0.002; //extra gravity
if (!(game.cycle % this.lookFrequency)) { //find mob targets if (!(game.cycle % this.lookFrequency)) { //find mob targets
const pos = {
x: this.position.x,
y: this.position.y - 8 //look from a bit higher to see things even with debris
}
for (let i = 0, len = mob.length; i < len; ++i) { for (let i = 0, len = mob.length; i < len; ++i) {
const dist = Vector.magnitudeSquared(Vector.sub(pos, mob[i].position)); if (Vector.magnitudeSquared(Vector.sub(this.seeFrom, mob[i].position)) < 500000 &&
if (dist < 500000 && //range2 = 700*700
mob[i].dropPowerUp && mob[i].dropPowerUp &&
Matter.Query.ray(map, pos, mob[i].position).length === 0 && Matter.Query.ray(map, this.seeFrom, mob[i].position).length === 0 &&
Matter.Query.ray(body, pos, mob[i].position).length === 0) { Matter.Query.ray(body, this.seeFrom, mob[i].position).length === 0) {
this.endCycle = 0 //end life if mob is near and visible this.endCycle = 0 //end life if mob is near and visible
} }
} }
} }
} }
} }
bullet[me].do = function () {
this.force.y += this.mass * 0.002; //extra gravity
let collide = Matter.Query.collides(this, map) //check if collides with map
if (collide.length > 0) {
for (let i = 0; i < collide.length; i++) {
if (collide[i].bodyA.collisionFilter.category === cat.map || collide[i].bodyB.collisionFilter.category === cat.map) {
this.seeFrom = Vector.add(this.position, Vector.mult(collide[i].normal, -20)) //find the location 20 pixels perpendicular to the map
Matter.Body.setStatic(this, true)
this.arm();
}
}
} else { //check if collides with a body
collide = Matter.Query.collides(this, body)
if (collide.length > 0) {
for (let i = 0; i < collide.length; i++) {
if (collide[i].bodyA.collisionFilter.category === cat.body || collide[i].bodyB.collisionFilter.category === cat.body) {
this.seeFrom = this.position
this.arm();
}
}
}
}
} }
bullet[me].onEnd = function () { bullet[me].onEnd = function () {
const pos = { if (!this.seeFrom) this.seeFrom = this.position
x: this.position.x,
y: this.position.y - 8 //aim from a bit higher to hit things even with debris
}
ctx.beginPath();
ctx.arc(pos.x, pos.y, 5, 0, 2 * Math.PI);
ctx.fill();
const targets = [] //target nearby mobs const targets = [] //target nearby mobs
for (let i = 0, len = mob.length; i < len; i++) { for (let i = 0, len = mob.length; i < len; i++) {
if (mob[i].dropPowerUp) { if (mob[i].dropPowerUp) {
const dist = Vector.magnitudeSquared(Vector.sub(pos, mob[i].position)); const dist = Vector.magnitudeSquared(Vector.sub(this.seeFrom, mob[i].position));
if (dist < 1440000 && //1200*1200 if (dist < 1440000 && //1200*1200
Matter.Query.ray(map, pos, mob[i].position).length === 0 && Matter.Query.ray(map, this.seeFrom, mob[i].position).length === 0 &&
Matter.Query.ray(body, pos, mob[i].position).length === 0) { Matter.Query.ray(body, this.seeFrom, mob[i].position).length === 0) {
//predict where the mob will be in a few cycles targets.push(Vector.add(mob[i].position, Vector.mult(mob[i].velocity, Math.sqrt(dist) / 60))) //predict where the mob will be in a few cycles
targets.push(Vector.add(mob[i].position, Vector.mult(mob[i].velocity, Math.sqrt(dist) / 60)))
} }
} }
} }
@@ -1688,28 +1851,19 @@ const b = {
x: targets[index].x + SPREAD * (Math.random() - 0.5), x: targets[index].x + SPREAD * (Math.random() - 0.5),
y: targets[index].y + SPREAD * (Math.random() - 0.5) y: targets[index].y + SPREAD * (Math.random() - 0.5)
} }
needle(pos, Vector.mult(Vector.normalise(Vector.sub(WHERE, pos)), speed)) b.nail(this.seeFrom, Vector.mult(Vector.normalise(Vector.sub(WHERE, this.seeFrom)), speed), 0.5)
} else { // aim in random direction } else { // aim in random direction
const ANGLE = 2 * Math.PI * Math.random() const ANGLE = 2 * Math.PI * Math.random()
needle(pos, { b.nail(this.seeFrom, {
x: speed * Math.cos(ANGLE), x: speed * Math.cos(ANGLE),
y: speed * Math.sin(ANGLE) y: speed * Math.sin(ANGLE)
}) })
} }
function needle(pos, velocity) {
const me = bullet.length;
bullet[me] = Bodies.rectangle(pos.x, pos.y, 25 * b.modBulletSize, 2 * b.modBulletSize, b.fireAttributes(Math.atan2(velocity.y, velocity.x)));
Matter.Body.setVelocity(bullet[me], velocity);
World.add(engine.world, bullet[me]); //add bullet to world
bullet[me].endCycle = game.cycle + 60 + 18 * Math.random();
bullet[me].dmg = 0.8
bullet[me].do = function () {};
} }
} }
} }
} },
}, { {
name: "spores", //11 name: "spores", //11
description: "fire orbs that discharge <strong style='letter-spacing: 2px;'>spores</strong><br><strong style='letter-spacing: 2px;'>spores</strong> seek out enemies", description: "fire orbs that discharge <strong style='letter-spacing: 2px;'>spores</strong><br><strong style='letter-spacing: 2px;'>spores</strong> seek out enemies",
ammo: 0, ammo: 0,
@@ -2034,7 +2188,7 @@ const b = {
}, },
{ {
name: "pulse", //15 name: "pulse", //15
description: "pump a <strong>laser</strong> that initiates a fusion <strong class='color-e'>explosion</strong><br>each pulse drains 25% of your current <strong class='color-f'>energy</strong>", description: "convert 25% of your <strong class='color-f'>energy</strong> into a pulsed laser<br>instantly initiates a fusion <strong class='color-e'>explosion</strong>",
ammo: 0, ammo: 0,
ammoPack: Infinity, ammoPack: Infinity,
have: false, have: false,

View File

@@ -74,10 +74,22 @@ function playerHeadCheck(event) {
} }
} }
function mobCollisionChecks(event) { function collisionChecks(event) {
const pairs = event.pairs; const pairs = event.pairs;
for (let i = 0, j = pairs.length; i != j; i++) { for (let i = 0, j = pairs.length; i != j; i++) {
// //map + bullet collisions
// if (pairs[i].bodyA.collisionFilter.category === cat.map && pairs[i].bodyB.collisionFilter.category === cat.bullet) {
// collideBulletStatic(pairs[i].bodyB)
// } else if (pairs[i].bodyB.collisionFilter.category === cat.map && pairs[i].bodyA.collisionFilter.category === cat.bullet) {
// collideBulletStatic(pairs[i].bodyA)
// }
// //triggers when the bullets hits something static
// function collideBulletStatic(obj, speedThreshold = 12, massThreshold = 2) {
// if (obj.onWallHit) obj.onWallHit();
// }
//body + player collision //body + player collision
if (game.isBodyDamage) { if (game.isBodyDamage) {
if (pairs[i].bodyA === playerBody || pairs[i].bodyA === playerHead) { if (pairs[i].bodyA === playerBody || pairs[i].bodyA === playerHead) {
@@ -126,6 +138,7 @@ function mobCollisionChecks(event) {
let dmg = Math.min(Math.max(0.025 * Math.sqrt(mob[k].mass), 0.05), 0.3) * game.dmgScale; //player damage is capped at 0.3*dmgScale of 1.0 let dmg = Math.min(Math.max(0.025 * Math.sqrt(mob[k].mass), 0.05), 0.3) * game.dmgScale; //player damage is capped at 0.3*dmgScale of 1.0
mech.damage(dmg); mech.damage(dmg);
if (mob[k].onHit) mob[k].onHit(k); if (mob[k].onHit) mob[k].onHit(k);
mech.fieldMeter += b.modPiezo
if (b.isModAnnihilation && mob[k].dropPowerUp && !mob[k].isShielded) { if (b.isModAnnihilation && mob[k].dropPowerUp && !mob[k].isShielded) {
mob[k].death(); mob[k].death();
game.drawList.push({ game.drawList.push({
@@ -205,7 +218,7 @@ function mobCollisionChecks(event) {
Events.on(engine, "collisionStart", function (event) { Events.on(engine, "collisionStart", function (event) {
playerOnGroundCheck(event); playerOnGroundCheck(event);
playerHeadCheck(event); playerHeadCheck(event);
mobCollisionChecks(event); collisionChecks(event);
}); });
Events.on(engine, "collisionActive", function (event) { Events.on(engine, "collisionActive", function (event) {
playerOnGroundCheck(event); playerOnGroundCheck(event);

View File

@@ -213,7 +213,9 @@ const game = {
}, },
switchGun() { switchGun() {
if (b.modNoAmmo) b.modNoAmmo = 1 //this prevents hacking the mod by switching guns if (b.modNoAmmo) b.modNoAmmo = 1 //this prevents hacking the mod by switching guns
// if (b.guns[b.activeGun].switchOff) b.guns[b.activeGun].switchOff(); //run code when switching away from a gun
b.activeGun = b.inventory[b.inventoryGun]; b.activeGun = b.inventory[b.inventoryGun];
// if (b.guns[b.activeGun].switchOn) b.guns[b.activeGun].switchOn(); //run code when switching to a new gun
game.updateGunHUD(); game.updateGunHUD();
game.boldActiveGunHUD(); game.boldActiveGunHUD();
// mech.drop(); // mech.drop();
@@ -435,6 +437,7 @@ const game = {
b.guns[i].have = false; b.guns[i].have = false;
if (b.guns[i].ammo != Infinity) b.guns[i].ammo = 0; if (b.guns[i].ammo != Infinity) b.guns[i].ammo = 0;
} }
// if (b.activeGun && b.guns[b.activeGun].switchOff) b.guns[b.activeGun].switchOff(); //run code when switching away from a gun
b.activeGun = null; b.activeGun = null;
b.setModDefaults(); //remove mods b.setModDefaults(); //remove mods
game.updateModHUD(); game.updateModHUD();

View File

@@ -2,12 +2,30 @@
/* TODO: ******************************************* /* TODO: *******************************************
***************************************************** *****************************************************
add new power up class: rerolls add setting for random drops instead of choosing
let you repopulate a power up selection menu
mines: move targeting position to be perpendicular to stuck wall
mines change shape of mine (maybe a octagon?)
mines: collide with bots
probably don't have to fix...
mines: add high friction, like vacuum bomb and trigger static mode after not moving for a bit
no need to watch collisions
rework custom mode
custom mode grey out mods that are bad, like selection based mods
enable recursive mods
remove 5 mod cap on custom mode
change nail-bot's movement
maybe have it move in a circle around player?
high friction very high acceleration towards circle location
add mouse constraint in testing mode
https://github.com/liabru/matter-js/blob/master/examples/events.js
weekly random challenge where everyone playing each week gets the same random setup. weekly random challenge where everyone playing each week gets the same random setup.
The randomness would be determined by the date so it would sync everyone. The randomness would be determined by the date so it would sync everyone.
powerups still drop, but the drops are determined by a preset list that changes each week. power ups still drop, but the drops are determined by a preset list that changes each week.
mod: do something at the end of each level mod: do something at the end of each level
heal to full heal to full
@@ -18,28 +36,10 @@ mod: do something at the end of each level
take no damage take no damage
don't shoot don't shoot
selection options for field to stay with current
custom mode grey out mods that are bad, like selection based mods
not important
custom mode can't use recursive mods
field graphics too dark at high energy
not important
rewrite pause as a change to the main loop rewrite pause as a change to the main loop
not important not important
like testing loop like testing loop
game setting for slower computers
fewer blocks
fewer debris
fewer mobs
mod: gain energy after taking damage
use piezoelectric name (already used)
mod: ground stomp on enterLand() mod: ground stomp on enterLand()
mod: if you fire when out of ammo you gain 1 ammo pack at the cost of mod: if you fire when out of ammo you gain 1 ammo pack at the cost of
@@ -89,7 +89,7 @@ new map with repeating endlessness
field power up effects field power up effects
field allows player to hold and throw living mobs field allows player to hold and throw living mobs
of hack mobs and hack mobs
give mobs more animal-like behaviors give mobs more animal-like behaviors
like rain world like rain world

View File

@@ -16,7 +16,7 @@ const level = {
// game.difficulty = 6; //for testing to simulate possible mobs spawns // game.difficulty = 6; //for testing to simulate possible mobs spawns
// b.giveGuns(10) // b.giveGuns(10)
// mech.setField(3) // mech.setField(3)
// b.giveMod(16); // b.giveMod(3);
level.intro(); //starting level level.intro(); //starting level
// level.testingMap(); // level.testingMap();
@@ -37,9 +37,12 @@ const level = {
game.setZoom(); game.setZoom();
level.addToWorld(); //add bodies to game engine level.addToWorld(); //add bodies to game engine
game.draw.setPaths(); game.draw.setPaths();
for (let i = 0; i < b.modGuardianCount; i++) { for (let i = 0; i < b.modLaserBotCount; i++) {
b.guardian() b.guardian()
} }
for (let i = 0; i < b.modNailBotCount; i++) {
b.nailBot()
}
}, },
isBuildRun: false, isBuildRun: false,
difficultyIncrease(num = 1) { difficultyIncrease(num = 1) {

View File

@@ -936,7 +936,9 @@ const mobs = {
dmg /= Math.sqrt(this.mass) dmg /= Math.sqrt(this.mass)
if (this.shield) dmg *= 0.04 if (this.shield) dmg *= 0.04
if (b.isModLowHealthDmg) dmg *= (3 / (2 + mech.health)) //up to 50% dmg at zero player health if (b.isModLowHealthDmg) dmg *= (3 / (2 + mech.health)) //up to 50% dmg at zero player health
if (b.isModFarAwayDmg) dmg *= 1 + Math.sqrt(Math.max(1000, Math.min(3500, this.distanceToPlayer())) - 1000) * 0.01 //up to 50% dmg at max range of 3500
// if (b.isModFarAwayDmg) dmg *= 1 + Math.sqrt(Math.max(1000, Math.min(3500, this.distanceToPlayer())) - 1000) * 0.01 //up to 50% dmg at max range of 3500
if (b.isModFarAwayDmg) dmg *= 1 + Math.sqrt(Math.max(500, Math.min(3000, this.distanceToPlayer())) - 500) * 0.0067 //up to 50% dmg at max range of 3500
if (b.modEnergySiphon && dmg !== Infinity) mech.fieldMeter += Math.min(this.health, dmg) * b.modEnergySiphon if (b.modEnergySiphon && dmg !== Infinity) mech.fieldMeter += Math.min(this.health, dmg) * b.modEnergySiphon
if (b.modHealthDrain && dmg !== Infinity) mech.addHealth(Math.min(this.health, dmg) * b.modHealthDrain) if (b.modHealthDrain && dmg !== Infinity) mech.addHealth(Math.min(this.health, dmg) * b.modHealthDrain)
this.health -= dmg this.health -= dmg

View File

@@ -311,8 +311,10 @@ const mech = {
//find what mods I don't have //find what mods I don't have
let options = []; let options = [];
for (let i = 0, len = b.mods.length; i < len; i++) { for (let i = 0, len = b.mods.length; i < len; i++) {
//can't get quantum immortality again //can't get quantum immortality or multiverse
if (b.mods[i].name !== "quantum immortality" && b.mods[i].count < b.mods[i].maxCount) options.push(i); if (b.mods[i].name !== "quantum immortality" &&
b.mods[i].name !== "level II multiverse" &&
b.mods[i].count < b.mods[i].maxCount) options.push(i);
} }
//add a new mod //add a new mod
if (options.length > 0) { if (options.length > 0) {
@@ -439,12 +441,9 @@ const mech = {
damage(dmg) { damage(dmg) {
if (b.isModEntanglement && b.inventory[0] === b.activeGun) { if (b.isModEntanglement && b.inventory[0] === b.activeGun) {
for (let i = 0, len = b.inventory.length; i < len; i++) { for (let i = 0, len = b.inventory.length; i < len; i++) {
dmg *= 0.93 dmg *= 0.9
} }
} }
if (b.modPiezo) {
mech.fieldMeter += dmg * b.modPiezo
}
mech.health -= dmg; mech.health -= dmg;
if (mech.health < 0) { if (mech.health < 0) {
mech.health = 0; mech.health = 0;

View File

@@ -217,12 +217,12 @@ const powerUps = {
if (Math.random() < b.isModBayesian) powerUps.spawn(x, y, "ammo"); if (Math.random() < b.isModBayesian) powerUps.spawn(x, y, "ammo");
return; return;
} }
if (Math.random() < 0.0035 * (3 - b.inventory.length)) { //a new gun has a low chance for each not acquired gun up to 4 if (Math.random() < 0.0025 * (3 - b.inventory.length)) { //a new gun has a low chance for each not acquired gun up to 3
powerUps.spawn(x, y, "gun"); powerUps.spawn(x, y, "gun");
if (Math.random() < b.isModBayesian) powerUps.spawn(x, y, "gun"); if (Math.random() < b.isModBayesian) powerUps.spawn(x, y, "gun");
return; return;
} }
if (Math.random() < 0.0032 * (10 - b.modCount)) { //a new mod has a low chance for each not acquired mod up to 7 if (Math.random() < 0.003 * (11 - b.modCount)) { //a new mod has a low chance for each not acquired mod up to 7
powerUps.spawn(x, y, "mod"); powerUps.spawn(x, y, "mod");
if (Math.random() < b.isModBayesian) powerUps.spawn(x, y, "mod"); if (Math.random() < b.isModBayesian) powerUps.spawn(x, y, "mod");
return; return;
@@ -237,13 +237,13 @@ const powerUps = {
if (mech.fieldMode === 0) { if (mech.fieldMode === 0) {
powerUps.spawn(x, y, "field") powerUps.spawn(x, y, "field")
if (Math.random() < b.isModBayesian) powerUps.spawn(x, y, "field") if (Math.random() < b.isModBayesian) powerUps.spawn(x, y, "field")
} else if (Math.random() < 0.6) { } else if (Math.random() < 0.65) {
powerUps.spawn(x, y, "mod") powerUps.spawn(x, y, "mod")
if (Math.random() < b.isModBayesian) powerUps.spawn(x, y, "mod") if (Math.random() < b.isModBayesian) powerUps.spawn(x, y, "mod")
} else if (Math.random() < 0.1) { } else if (Math.random() < 0.06) {
powerUps.spawn(x, y, "gun") powerUps.spawn(x, y, "gun")
if (Math.random() < b.isModBayesian) powerUps.spawn(x, y, "gun") if (Math.random() < b.isModBayesian) powerUps.spawn(x, y, "gun")
} else if (Math.random() < 0.1) { } else if (Math.random() < 0.15) {
powerUps.spawn(x, y, "field"); powerUps.spawn(x, y, "field");
if (Math.random() < b.isModBayesian) powerUps.spawn(x, y, "field"); if (Math.random() < b.isModBayesian) powerUps.spawn(x, y, "field");
} else if (mech.health < 0.65) { } else if (mech.health < 0.65) {

View File

@@ -330,6 +330,13 @@ em {
letter-spacing: 1px; letter-spacing: 1px;
} }
.color-m {
color: rgb(115, 61, 202);
letter-spacing: 1px;
}
.faded { .faded {
opacity: 0.7; opacity: 0.7;
font-size: 90%; font-size: 90%;