fragments

so many bug fixes around CPT
mod: fragments - blocks, grenades, rail gun, shotgun slugs can all eject nails on collisions, or detonation
This commit is contained in:
landgreen
2020-12-10 06:55:00 -08:00
parent 46fbb90d8d
commit 75f6f268eb
8 changed files with 106 additions and 260 deletions

View File

@@ -24,7 +24,7 @@ const b = {
if (mod.isAmmoFromHealth) {
if (mech.health > 2 * mod.isAmmoFromHealth * mech.maxHealth) {
mech.damage(mod.isAmmoFromHealth * mech.maxHealth / mech.harmReduction());
powerUps.spawn(mech.pos.x, mech.pos.y, "ammo");
if (!(mod.isRewindAvoidDeath && mech.energy > 0.66)) powerUps.spawn(mech.pos.x, mech.pos.y, "ammo"); //don't give ammo if CPT triggered
} else {
game.replaceTextLog = true;
game.makeTextLog("not enough health for catabolism to produce ammo", 120);
@@ -285,7 +285,7 @@ const b = {
bullet[me].explodeRad = 275;
bullet[me].onEnd = function() {
b.explosion(this.position, this.explodeRad); //makes bullet do explosive damage at end
if (mod.grenadeFragments) b.targetedNail(this.position, mod.grenadeFragments)
if (mod.fragments) b.targetedNail(this.position, mod.fragments * 5)
}
bullet[me].minDmgSpeed = 1;
bullet[me].beforeDmg = function() {
@@ -310,7 +310,7 @@ const b = {
bullet[me].explodeRad = 275;
bullet[me].onEnd = function() {
b.explosion(this.position, this.explodeRad); //makes bullet do explosive damage at end
if (mod.grenadeFragments) b.targetedNail(this.position, mod.grenadeFragments)
if (mod.fragments) b.targetedNail(this.position, mod.fragments * 5)
}
bullet[me].minDmgSpeed = 1;
bullet[me].beforeDmg = function() {
@@ -345,7 +345,7 @@ const b = {
bullet[me].explodeRad = 325 + Math.floor(Math.random() * 50);;
bullet[me].onEnd = function() {
b.explosion(this.position, this.explodeRad); //makes bullet do explosive damage at end
if (mod.grenadeFragments) b.targetedNail(this.position, mod.grenadeFragments)
if (mod.fragments) b.targetedNail(this.position, mod.fragments * 7)
}
bullet[me].beforeDmg = function() {};
bullet[me].restitution = 0.4;
@@ -426,14 +426,6 @@ const b = {
bullet[me].stuckTo = null;
bullet[me].stuckToRelativePosition = null;
bullet[me].vacuumSlow = 0.97;
if (mod.isRewindGrenade && input.down) {
Matter.Body.setVelocity(bullet[me], {
x: 0,
y: 0
});
bullet[me].maxDamageRadius *= 1.3
mech.rewind(200, false)
}
bullet[me].beforeDmg = function() {};
bullet[me].stuck = function() {};
bullet[me].do = function() {
@@ -2300,6 +2292,14 @@ const b = {
}
}
};
if (mod.fragments) {
bullet[me].beforeDmg = function() {
if (this.speed > 4) {
b.targetedNail(this.position, mod.fragments * 8)
this.endCycle = 0 //triggers despawn
}
}
}
} else if (mod.isIncendiary) {
const SPEED = mech.crouch ? 35 : 25
const END = Math.floor(mech.crouch ? 9 : 6);
@@ -2716,162 +2716,6 @@ const b = {
mech.fireCDcycle = mech.cycle + Math.floor((mech.crouch ? 40 : 30) * b.fireCD); // cool down
b.grenade()
},
fireNeutron() {
const me = bullet.length;
const dir = mech.angle;
bullet[me] = Bodies.polygon(mech.pos.x + 30 * Math.cos(mech.angle), mech.pos.y + 30 * Math.sin(mech.angle), 10, 4, b.fireAttributes(dir, false));
b.fireProps(mech.crouch ? 45 : 25, mech.crouch ? 35 : 20, dir, me); //cd , speed
Matter.Body.setDensity(bullet[me], 0.000001);
bullet[me].endCycle = Infinity;
bullet[me].frictionAir = 0;
bullet[me].friction = 1;
bullet[me].frictionStatic = 1;
bullet[me].restitution = 0;
bullet[me].minDmgSpeed = 0;
bullet[me].damageRadius = 100;
bullet[me].maxDamageRadius = 450 + 130 * mod.isNeutronSlow + 130 * mod.isNeutronImmune //+ 150 * Math.random()
bullet[me].radiusDecay = (0.81 + 0.15 * mod.isNeutronSlow + 0.15 * mod.isNeutronImmune) / mod.isBulletsLastLonger
bullet[me].stuckTo = null;
bullet[me].stuckToRelativePosition = null;
bullet[me].vacuumSlow = 0.97;
if (mod.isRewindGrenade && input.down) {
Matter.Body.setVelocity(bullet[me], {
x: 0,
y: 0
});
bullet[me].maxDamageRadius *= 1.3
mech.rewind(200, false)
}
bullet[me].beforeDmg = function() {};
bullet[me].stuck = function() {};
bullet[me].do = function() {
function onCollide(that) {
that.collisionFilter.mask = 0; //non collide with everything
Matter.Body.setVelocity(that, {
x: 0,
y: 0
});
that.do = that.radiationMode;
}
const mobCollisions = Matter.Query.collides(this, mob)
if (mobCollisions.length) {
onCollide(this)
this.stuckTo = mobCollisions[0].bodyA
mobs.statusDoT(this.stuckTo, 0.5, 360) //apply radiation damage status effect on direct hits
if (this.stuckTo.isVerticesChange) {
this.stuckToRelativePosition = {
x: 0,
y: 0
}
} else {
//find the relative position for when the mob is at angle zero by undoing the mobs rotation
this.stuckToRelativePosition = Vector.rotate(Vector.sub(this.position, this.stuckTo.position), -this.stuckTo.angle)
}
this.stuck = function() {
if (this.stuckTo && this.stuckTo.alive) {
const rotate = Vector.rotate(this.stuckToRelativePosition, this.stuckTo.angle) //add in the mob's new angle to the relative position vector
Matter.Body.setPosition(this, Vector.add(Vector.add(rotate, this.stuckTo.velocity), this.stuckTo.position))
Matter.Body.setVelocity(this, this.stuckTo.velocity); //so that it will move properly if it gets unstuck
} else {
this.collisionFilter.mask = cat.map | cat.body | cat.player | cat.mob; //non collide with everything but map
this.stuck = function() {
this.force.y += this.mass * 0.001;
}
}
}
} else {
const bodyCollisions = Matter.Query.collides(this, body)
if (bodyCollisions.length) {
if (!bodyCollisions[0].bodyA.isNotHoldable) {
onCollide(this)
this.stuckTo = bodyCollisions[0].bodyA
//find the relative position for when the mob is at angle zero by undoing the mobs rotation
this.stuckToRelativePosition = Vector.rotate(Vector.sub(this.position, this.stuckTo.position), -this.stuckTo.angle)
} else {
this.do = this.radiationMode;
}
this.stuck = function() {
if (this.stuckTo) {
const rotate = Vector.rotate(this.stuckToRelativePosition, this.stuckTo.angle) //add in the mob's new angle to the relative position vector
Matter.Body.setPosition(this, Vector.add(Vector.add(rotate, this.stuckTo.velocity), this.stuckTo.position))
// Matter.Body.setVelocity(this, this.stuckTo.velocity); //so that it will move properly if it gets unstuck
} else {
this.force.y += this.mass * 0.001;
}
}
} else {
if (Matter.Query.collides(this, map).length) {
onCollide(this)
} else { //if colliding with nothing just fall
this.force.y += this.mass * 0.001;
}
}
}
}
bullet[me].radiationMode = function() { //the do code after the bullet is stuck on something, projects a damaging radiation field
this.stuck(); //runs different code based on what the bullet is stuck to
if (!mech.isBodiesAsleep) {
this.damageRadius = this.damageRadius * 0.85 + 0.15 * this.maxDamageRadius //smooth radius towards max
this.maxDamageRadius -= this.radiusDecay
if (this.damageRadius < 15) {
this.endCycle = 0;
} else {
//aoe damage to player
if (!mod.isNeutronImmune && Vector.magnitude(Vector.sub(player.position, this.position)) < this.damageRadius) {
const DRAIN = 0.0023
if (mech.energy > DRAIN) {
mech.energy -= DRAIN
} else {
mech.energy = 0;
mech.damage(0.00015)
}
}
//aoe damage to mobs
for (let i = 0, len = mob.length; i < len; i++) {
if (Vector.magnitude(Vector.sub(mob[i].position, this.position)) < this.damageRadius) {
let dmg = b.dmgScale * 0.082
if (Matter.Query.ray(map, mob[i].position, this.position).length > 0) dmg *= 0.25 //reduce damage if a wall is in the way
if (mob[i].shield) dmg *= 4 //x5 to make up for the /5 that shields normally take
mob[i].damage(dmg);
mob[i].locatePlayer();
if (mod.isNeutronSlow) {
Matter.Body.setVelocity(mob[i], {
x: mob[i].velocity.x * this.vacuumSlow,
y: mob[i].velocity.y * this.vacuumSlow
});
}
}
}
ctx.beginPath();
ctx.arc(this.position.x, this.position.y, this.damageRadius, 0, 2 * Math.PI);
ctx.globalCompositeOperation = "lighter"
ctx.fillStyle = `rgba(25,139,170,${0.2+0.06*Math.random()})`;
ctx.fill();
ctx.globalCompositeOperation = "source-over"
if (mod.isNeutronSlow) {
const that = this
function slow(who, radius = that.explodeRad * 3.2) {
for (i = 0, len = who.length; i < len; i++) {
const sub = Vector.sub(that.position, who[i].position);
const dist = Vector.magnitude(sub);
if (dist < radius) {
Matter.Body.setVelocity(who[i], {
x: who[i].velocity.x * that.vacuumSlow,
y: who[i].velocity.y * that.vacuumSlow
});
}
}
}
slow(body, this.damageRadius)
slow([player], this.damageRadius)
}
}
}
}
},
},
{
name: "mine",
@@ -3156,8 +3000,8 @@ const b = {
});
// Matter.Body.setDensity(this, 0.001);
}
if (mod.isRailNails && this.speed > 10) {
b.targetedNail(this.position, (Math.min(40, this.speed) - 10) * 0.6) // 0.6 as many nails as the normal rail gun
if (mod.fragments && this.speed > 10) {
b.targetedNail(this.position, mod.fragments * 10)
this.endCycle = 0 //triggers despawn
}
},
@@ -3243,8 +3087,8 @@ const b = {
});
// Matter.Body.setDensity(this, 0.001);
}
if (mod.isRailNails && this.speed > 10) {
b.targetedNail(this.position, Math.min(40, this.speed) - 10)
if (mod.fragments && this.speed > 10) {
b.targetedNail(this.position, mod.fragments * 16)
this.endCycle = 0 //triggers despawn
}
},

View File

@@ -103,8 +103,12 @@ function collisionChecks(event) {
) {
mob[k].foundPlayer();
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
if (mod.isRewindAvoidDeath && mech.energy > 0.66) { //CPT reversal runs in mech.damage, but it stops the rest of the collision code here too
mech.damage(dmg);
return
}
mech.damage(dmg);
if (mod.isPiezo) mech.energy += mech.maxEnergy * 2;
if (mod.isPiezo) mech.energy += 200;
if (mod.isBayesian) powerUps.ejectMod()
if (mob[k].onHit) mob[k].onHit(k);
mech.immuneCycle = mech.cycle + mod.collisionImmuneCycles; //player is immune to collision damage for 30 cycles
@@ -168,6 +172,10 @@ function collisionChecks(event) {
const stunTime = dmg / Math.sqrt(obj.mass)
if (stunTime > 0.5) mobs.statusStun(mob[k], 30 + 60 * Math.sqrt(stunTime))
if (mob[k].distanceToPlayer2() < 1000000 && !mech.isCloak) mob[k].foundPlayer();
if (mod.fragments && obj.speed > 10 && !obj.hasFragmented) {
obj.hasFragmented = true;
b.targetedNail(obj.position, mod.fragments * 4)
}
game.drawList.push({
x: pairs[i].activeContacts[0].vertex.x,
y: pairs[i].activeContacts[0].vertex.y,

View File

@@ -277,7 +277,7 @@ const game = {
if (b.inventory[0] === b.activeGun) {
let lessDamage = 1
for (let i = 0, len = b.inventory.length; i < len; i++) {
lessDamage *= 0.87 // 1 - 0.15
lessDamage *= 0.87 // 1 - 0.13
}
document.getElementById("mod-entanglement").innerHTML = " " + ((1 - lessDamage) * 100).toFixed(0) + "%"
} else {

View File

@@ -20,7 +20,7 @@ const level = {
// b.giveGuns("grenades")
// mod.isIncendiary = true
// mod.is3Missiles = true
// mod.giveMod("CPT reversal")
// mod.giveMod("neutron bomb")
// mod.giveMod("causality bombs")
level.intro(); //starting level
@@ -236,6 +236,16 @@ const level = {
height: 350,
color: "rgba(0,255,255,0.1)"
});
powerUps.spawn(1675, -50, "ammo");
powerUps.spawn(3350, -75, "ammo");
powerUps.spawn(3925, -50, "ammo");
powerUps.spawn(4550, -75, "ammo");
powerUps.spawn(5225, -50, "ammo");
powerUps.spawn(5475, -350, "ammo");
powerUps.spawn(5625, -350, "ammo");
powerUps.spawn(5575, -425, "ammo");
powerUps.spawn(5550, -400, "ammo");
powerUps.spawn(5575, -425, "ammo");
spawn.mapRect(-1950, 0, 8200, 1800); //ground
spawn.mapRect(-1950, -1500, 1800, 1900); //left wall

View File

@@ -150,7 +150,7 @@ const mobs = {
}
},
statusDoT(who, tickDamage, cycles = 180) {
if (!who.isShielded && !mech.isBodiesAsleep) {
if (!who.isShielded && !mech.isBodiesAsleep && who.alive) {
who.status.push({
effect() {
if ((game.cycle - this.startCycle) % 30 === 0) {

View File

@@ -372,6 +372,22 @@ const mod = {
mod.throwChargeRate = 1
}
},
{
name: "fragmentation",
description: "detonation or collision ejects <strong>nails</strong><br><em>rail gun, grenades, shotgun slugs, blocks</em>",
maxCount: 9,
count: 0,
allowed() {
return (mod.haveGunCheck("grenades") && !mod.isNeutronBomb) || mod.haveGunCheck("rail gun") || (mod.haveGunCheck("shotgun") && mod.isSlugShot) || mod.throwChargeRate > 1
},
requires: "grenades, rail gun, shotgun slugs, or mass driver",
effect() {
mod.fragments++
},
remove() {
mod.fragments = 0
}
},
{
name: "ammonium nitrate",
description: "increase <strong class='color-e'>explosive</strong> <strong class='color-d'>damage</strong> by <strong>20%</strong><br>increase <strong class='color-e'>explosive</strong> <strong>radius</strong> by <strong>20%</strong>",
@@ -1044,9 +1060,9 @@ const mod = {
maxCount: 1,
count: 0,
allowed() { //&& (mech.fieldUpgrades[mech.fieldMode].name !== "nano-scale manufacturing" || mech.maxEnergy > 1)
return mech.maxEnergy > 0.99 && mech.fieldUpgrades[mech.fieldMode].name !== "standing wave harmonics" && !mod.isEnergyHealth && !mod.isEnergyLoss && !mod.isPiezo
return mech.maxEnergy > 0.99 && mech.fieldUpgrades[mech.fieldMode].name !== "standing wave harmonics" && !mod.isEnergyHealth
},
requires: "not nano-scale, mass-energy, standing wave, acute stress, piezoelectricity",
requires: "standing wave, mass-energy, piezoelectricity, max energy reduction",
effect() {
mod.isRewindAvoidDeath = true;
},
@@ -1092,12 +1108,12 @@ const mod = {
maxCount: 1,
count: 0,
allowed() {
return !mod.isEnergyHealth && !mod.isRewindAvoidDeath
return !mod.isEnergyHealth
},
requires: "not mass-energy equivalence, CPT reversal",
requires: "not mass-energy equivalence",
effect() {
mod.isPiezo = true;
mech.energy += mech.maxEnergy * 2;
mech.energy += 200;
},
remove() {
mod.isPiezo = false;
@@ -1893,7 +1909,7 @@ const mod = {
//**************************************************
{
name: "incendiary ammunition",
description: "<strong>bullets</strong> are loaded with <strong class='color-e'>explosives</strong><br><span style = 'font-size: 90%'>nail gun, shotgun, super balls, drones</span>",
description: "<strong>bullets</strong> are loaded with <strong class='color-e'>explosives</strong><br><em style = 'font-size: 90%'>nail gun, shotgun, super balls, drones</em>",
maxCount: 1,
count: 0,
allowed() {
@@ -1909,7 +1925,7 @@ const mod = {
},
{
name: "Lorentzian topology",
description: "<strong>bullets</strong> last <strong>30% longer</strong><br><span style = 'font-size: 83%'>drones, spores, missiles, foam, wave, ice IX, neutron</span>",
description: "<strong>bullets</strong> last <strong>30% longer</strong><br><em style = 'font-size: 83%'>drones, spores, missiles, foam, wave, ice IX, neutron</em>",
maxCount: 3,
count: 0,
allowed() {
@@ -2364,22 +2380,6 @@ const mod = {
mod.is3Missiles = false;
}
},
{
name: "fragmentation grenade",
description: "<strong>grenades</strong> are loaded with <strong>5</strong> nails<br>on detonation <strong>nails</strong> are ejected towards mobs",
maxCount: 9,
count: 0,
allowed() {
return mod.haveGunCheck("grenades") && !mod.isNeutronBomb
},
requires: "grenades, not neutron bomb",
effect() {
mod.grenadeFragments += 5
},
remove() {
mod.grenadeFragments = 0
}
},
{
name: "rocket-propelled grenade",
description: "<strong>grenades</strong> rapidly <strong>accelerate</strong> forward<br>map <strong>collisions</strong> trigger an <strong class='color-e'>explosion</strong>",
@@ -2422,7 +2422,7 @@ const mod = {
maxCount: 1,
count: 0,
allowed() {
return mod.haveGunCheck("grenades") && !mod.isRPG && !mod.grenadeFragments && !mod.isVacuumBomb
return mod.haveGunCheck("grenades") && !mod.isRPG && !mod.fragments && !mod.isVacuumBomb
},
requires: "grenades, not rocket-propelled or fragmentation",
effect() {
@@ -2504,7 +2504,7 @@ const mod = {
maxCount: 1,
count: 0,
allowed() {
return mod.isMineDrop + mod.nailBotCount + mod.grenadeFragments + mod.nailsDeathMob / 2 + (mod.haveGunCheck("mine") + mod.isRailNails + mod.isNailShot + (mod.haveGunCheck("nail gun") && !mod.isIncendiary)) * 2 > 1
return mod.isMineDrop + mod.nailBotCount + mod.fragments + mod.nailsDeathMob / 2 + (mod.haveGunCheck("mine") + mod.isNailShot + (mod.haveGunCheck("nail gun") && !mod.isIncendiary)) * 2 > 1
},
requires: "nails",
effect() {
@@ -2520,7 +2520,7 @@ const mod = {
maxCount: 1,
count: 0,
allowed() {
return mod.isMineDrop + mod.nailBotCount + mod.grenadeFragments + mod.nailsDeathMob / 2 + (mod.haveGunCheck("mine") + mod.isRailNails + mod.isNailShot + (mod.haveGunCheck("nail gun") && !mod.isIncendiary)) * 2 > 1
return mod.isMineDrop + mod.nailBotCount + mod.fragments + mod.nailsDeathMob / 2 + (mod.haveGunCheck("mine") + mod.isNailShot + (mod.haveGunCheck("nail gun") && !mod.isIncendiary)) * 2 > 1
},
requires: "nails",
effect() {
@@ -2805,22 +2805,6 @@ const mod = {
mod.isCapacitor = false;
}
},
{
name: "fragmenting projectiles",
description: "<strong>rail gun</strong> rods fragment into <strong>nails</strong><br>after hitting mobs at high speeds",
maxCount: 1,
count: 0,
allowed() {
return mod.haveGunCheck("rail gun")
},
requires: "rail gun",
effect() {
mod.isRailNails = true;
},
remove() {
mod.isRailNails = false;
}
},
{
name: "laser diodes",
description: "<strong>lasers</strong> drain <strong>37%</strong> less <strong class='color-f'>energy</strong><br><em>effects laser-gun and laser-bot</em>",
@@ -3575,7 +3559,6 @@ const mod = {
isFlechetteMultiShot: null,
isMineAmmoBack: null,
isPlasmaRange: null,
isRailNails: null,
isFreezeMobs: null,
recursiveMissiles: null,
isIceCrystals: null,
@@ -3587,7 +3570,7 @@ const mod = {
energyRegen: null,
isVacuumBomb: null,
renormalization: null,
grenadeFragments: null,
fragments: null,
isEnergyDamage: null,
isBotSpawner: null,
waveHelix: null,

View File

@@ -485,11 +485,36 @@ const mech = {
if (mod.energyRegen === 0) dmg *= 0.4 //0.22 + 0.78 * mech.energy //77% damage reduction at zero energy
if (mod.isTurret && mech.crouch) dmg *= 0.5;
if (mod.isEntanglement && b.inventory[0] === b.activeGun) {
for (let i = 0, len = b.inventory.length; i < len; i++) dmg *= 0.85 // 1 - 0.15
for (let i = 0, len = b.inventory.length; i < len; i++) dmg *= 0.87 // 1 - 0.15
}
return dmg
},
rewind(steps, isDrain = true) {
rewind(steps) {
if (mod.isRewindGrenade) {
for (let i = 1, len = Math.floor(1.5 + steps / 40); i < len; i++) {
b.grenade(Vector.add(mech.pos, { x: 10 * (Math.random() - 0.5), y: 10 * (Math.random() - 0.5) }), -i * Math.PI / len) //fire different angles for each grenade
const who = bullet[bullet.length - 1]
if (mod.isVacuumBomb) {
Matter.Body.setVelocity(who, {
x: who.velocity.x * 0.5,
y: who.velocity.y * 0.5
});
} else if (mod.isRPG) {
who.endCycle = (who.endCycle - game.cycle) * 0.2 + game.cycle
} else if (mod.isNeutronBomb) {
Matter.Body.setVelocity(who, {
x: who.velocity.x * 0.3,
y: who.velocity.y * 0.3
});
} else {
Matter.Body.setVelocity(who, {
x: who.velocity.x * 0.5,
y: who.velocity.y * 0.5
});
who.endCycle = (who.endCycle - game.cycle) * 0.5 + game.cycle
}
}
}
let history = mech.history[(mech.cycle - steps) % 300]
Matter.Body.setPosition(player, history.position);
Matter.Body.setVelocity(player, { x: history.velocity.x, y: history.velocity.y });
@@ -506,9 +531,7 @@ const mech = {
});
}
}
if (isDrain) {
mech.energy = Math.max(mech.energy - steps / 136, 0.01)
}
mech.energy = Math.max(mech.energy - steps / 136, 0.01)
mech.immuneCycle = mech.cycle + 30; //player is immune to collision damage for 30 cycles
let isDrawPlayer = true
@@ -539,13 +562,13 @@ const mech = {
};
if (mech.defaultFPSCycle < mech.cycle) requestAnimationFrame(shortPause);
game.fpsCap = (isDrain ? 3 : 5) //1 is longest pause, 4 is standard
game.fpsCap = 3 //1 is longest pause, 4 is standard
game.fpsInterval = 1000 / game.fpsCap;
mech.defaultFPSCycle = mech.cycle
if (mod.isRewindBot) {
const len = (isDrain ? steps * 0.042 : 2) * mod.isRewindBot
const len = steps * 0.042 * mod.isRewindBot
for (let i = 0; i < len; i++) {
where = mech.history[(mech.cycle - i * 40) % 300].position //spread out spawn locations along past history
const where = mech.history[Math.abs(mech.cycle - i * 40) % 300].position //spread out spawn locations along past history
b.randomBot({
x: where.x + 100 * (Math.random() - 0.5),
y: where.y + 100 * (Math.random() - 0.5)
@@ -556,32 +579,7 @@ const mech = {
},
damage(dmg) {
if (mod.isRewindAvoidDeath && mech.energy > 0.66) {
const steps = Math.floor(Math.min(299, 137 * mech.energy)) //go back 2 seconds at 100% energy
if (mod.isRewindGrenade) {
for (let i = 1, len = Math.floor(3 + steps / 60); i < len; i++) {
b.grenade(Vector.add(mech.pos, { x: 10 * (Math.random() - 0.5), y: 10 * (Math.random() - 0.5) }), -i * Math.PI / len) //fire different angles for each grenade
const who = bullet[bullet.length - 1]
if (mod.isVacuumBomb) {
Matter.Body.setVelocity(who, {
x: who.velocity.x * 0.5,
y: who.velocity.y * 0.5
});
} else if (mod.isRPG) {
who.endCycle = (who.endCycle - game.cycle) * 0.2 + game.cycle
} else if (mod.isNeutronBomb) {
Matter.Body.setVelocity(who, {
x: who.velocity.x * 0.3,
y: who.velocity.y * 0.3
});
} else {
Matter.Body.setVelocity(who, {
x: who.velocity.x * 0.5,
y: who.velocity.y * 0.5
});
who.endCycle = (who.endCycle - game.cycle) * 0.5 + game.cycle
}
}
}
const steps = Math.floor(Math.min(299, 137 * mech.energy))
mech.rewind(steps)
return
}