superfluidity

This commit is contained in:
landgreen
2020-07-02 19:36:06 -07:00
parent 00b01bb820
commit 00933c9f7e
10 changed files with 537 additions and 362 deletions

View File

@@ -1079,7 +1079,7 @@ const b = {
plasmaBot(position = mech.pos) {
const me = bullet.length;
const dir = mech.angle;
const RADIUS = 20
const RADIUS = 21
bullet[me] = Bodies.polygon(position.x, position.y, 5, RADIUS, {
angle: dir,
friction: 0,
@@ -1115,7 +1115,7 @@ const b = {
let closeDist = mod.isPlasmaRange * 1000;
for (let i = 0, len = mob.length; i < len; ++i) {
const DIST = Vector.magnitude(Vector.sub(this.position, mob[i].position)) - mob[i].radius;
if (DIST < closeDist && mob[i].dropPowerUp &&
if (DIST < closeDist &&
Matter.Query.ray(map, this.position, mob[i].position).length === 0 &&
Matter.Query.ray(body, this.position, mob[i].position).length === 0) {
closeDist = DIST;

View File

@@ -233,7 +233,10 @@ const game = {
if (mod.mods[i].count > 0) {
if (text) text += "<br>" //add a new line, but not on the first line
text += mod.mods[i].name
if (mod.mods[i].nameInfo) text += mod.mods[i].nameInfo
if (mod.mods[i].nameInfo) {
text += mod.mods[i].nameInfo
mod.mods[i].addNameInfo();
}
if (mod.mods[i].count > 1) text += ` (${mod.mods[i].count}x)`
}
}
@@ -243,7 +246,7 @@ const game = {
replaceTextLog: true,
// <!-- <path d="M832.41,106.64 V323.55 H651.57 V256.64 c0-82.5,67.5-150,150-150 Z" fill="#789" stroke="none" />
// <path d="M827,112 h30 a140,140,0,0,1,140,140 v68 h-167 z" fill="#7ce" stroke="none" /> -->
SVGleftMouse: '<svg viewBox="750 0 200 765" class="mouse-icon" width="40px" height = "60px" stroke-linecap="round" stroke-linejoin="round" stroke-width="25px" stroke="#000" fill="none"> <path fill="#fff" stroke="none" d="M827,112 h30 a140,140,0,0,1,140,140 v268 a140,140,0,0,1-140,140 h-60 a140,140,0,0,1-140-140v-268 a140,140,0,0,1,140-140h60" /> <path d="M832.41,106.64 V323.55 H651.57 V256.64 c0-82.5,67.5-150,150-150 Z" fill="#149" stroke="none" /> <path fill="none" d="M827,112 h30 a140,140,0,0,1,140,140 v268 a140,140,0,0,1-140,140 h-60 a140,140,0,0,1-140-140v-268 a140,140,0,0,1,140-140h60" /> <path d="M657 317 h 340 h-170 v-207" /> <ellipse fill="#fff" cx="827.57" cy="218.64" rx="29" ry="68" /> </svg>',
// SVGleftMouse: '<svg viewBox="750 0 200 765" class="mouse-icon" width="40px" height = "60px" stroke-linecap="round" stroke-linejoin="round" stroke-width="25px" stroke="#000" fill="none"> <path fill="#fff" stroke="none" d="M827,112 h30 a140,140,0,0,1,140,140 v268 a140,140,0,0,1-140,140 h-60 a140,140,0,0,1-140-140v-268 a140,140,0,0,1,140-140h60" /> <path d="M832.41,106.64 V323.55 H651.57 V256.64 c0-82.5,67.5-150,150-150 Z" fill="#149" stroke="none" /> <path fill="none" d="M827,112 h30 a140,140,0,0,1,140,140 v268 a140,140,0,0,1-140,140 h-60 a140,140,0,0,1-140-140v-268 a140,140,0,0,1,140-140h60" /> <path d="M657 317 h 340 h-170 v-207" /> <ellipse fill="#fff" cx="827.57" cy="218.64" rx="29" ry="68" /> </svg>',
SVGrightMouse: '<svg viewBox="750 0 200 765" class="mouse-icon" width="40px" height = "60px" stroke-linecap="round" stroke-linejoin="round" stroke-width="25px" stroke="#000" fill="none"> <path fill="#fff" stroke="none" d="M827,112 h30 a140,140,0,0,1,140,140 v268 a140,140,0,0,1-140,140 h-60 a140,140,0,0,1-140-140v-268 a140,140,0,0,1,140-140h60" /> <path d="M827,112 h30 a140,140,0,0,1,140,140 v68 h-167 z" fill="#0cf" stroke="none" /> <path fill="none" d="M827,112 h30 a140,140,0,0,1,140,140 v268 a140,140,0,0,1-140,140 h-60 a140,140,0,0,1-140-140v-268 a140,140,0,0,1,140-140h60" /> <path d="M657 317 h 340 h-170 v-207" /> <ellipse fill="#fff" cx="827.57" cy="218.64" rx="29" ry="68" /> </svg>',
makeTextLog(text, time = 180) {
if (game.replaceTextLog) {
@@ -400,6 +403,8 @@ const game = {
// game.noCameraScroll()
} else if (keys[85]) { // next level with U
level.nextLevel();
} else if (keys[88] && keys[90]) {
mech.death();
}
}
},
@@ -775,12 +780,6 @@ const game = {
if (mod.isHealthRecovery) mech.addHealth(0.01)
}
if (mod.isHealLowHealth) {
if (mech.health < mech.maxHealth * 0.25) {
mech.addHealth(0.01 * mech.maxHealth)
}
}
if (!(game.cycle % 420)) { //once every 7 seconds
fallCheck = function (who, save = false) {
let i = who.length;
@@ -1086,6 +1085,8 @@ const game = {
enableConstructMode() {
game.isConstructionMode = true;
game.isAutoZoom = false;
game.zoomScale = 2200;
game.setZoom();
document.body.addEventListener("mouseup", (e) => {
if (game.testing && game.constructMouseDownPosition) {

View File

@@ -248,7 +248,6 @@ const build = {
document.getElementById("difficulty-select").value = document.getElementById("difficulty-select-custom").value
localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
});
mod.resetModText();
},
reset() {
build.isCustomSelection = true;

View File

@@ -13,18 +13,16 @@ const level = {
// game.enableConstructMode() //used to build maps in testing mode
// level.difficultyIncrease(9)
// mech.isStealth = true;
// mod.giveMod("plasma-bot");
// mod.giveMod("nail-bot");
// mod.giveMod("laser-bot");
// mod.giveMod("boom-bot");
// mod.giveMod("supply chain");
// b.giveGuns("pulse")
b.giveGuns("ice IX")
// mech.setField("plasma torch")
level.intro(); //starting level
// level.bossRoom1()
// level.testing();
// level.stronghold()
// level.template()
// level.bosses();
// level.stronghold()
// level.satellite();
// level.skyscrapers();
// level.aerie();
@@ -32,6 +30,7 @@ const level = {
// level.warehouse();
// level.highrise();
// level.office();
} else {
spawn.setSpawnList(); //picks a couple mobs types for a themed random mob spawns
// spawn.pickList = ["focuser", "focuser"]
@@ -61,245 +60,86 @@ const level = {
if (mod.isArmorFromPowerUps) {
// for (let i = 0; i < powerUps.totalPowerUps; i++) {}
mech.maxHealth += 0.04 * powerUps.totalPowerUps
if (powerUps.totalPowerUps) game.makeTextLog("<span style='font-size:115%;'> max health increased by " + (0.04 * powerUps.totalPowerUps * 100).toFixed(0) + "%</span>", 300)
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)
}
},
isBuildRun: false,
difficultyIncrease(num = 1) {
// if (level.isBuildRun) num++
for (let i = 0; i < num; i++) {
game.difficulty++
game.dmgScale += 0.21; //damage done by mobs increases each level
b.dmgScale *= 0.91; //damage done by player decreases each level
game.accelScale *= 1.027 //mob acceleration increases each level
game.lookFreqScale *= 0.974 //mob cycles between looks decreases each level
game.CDScale *= 0.964 //mob CD time decreases each level
}
game.healScale = 1 / (1 + game.difficulty * 0.09) //a higher denominator makes for lower heals // mech.health += heal * game.healScale;
},
difficultyDecrease(num = 1) { //used in easy mode for game.reset()
for (let i = 0; i < num; i++) {
game.difficulty--
game.dmgScale -= 0.21; //damage done by mobs increases each level
if (game.dmgScale < 0.1) game.dmgScale = 0.1;
b.dmgScale /= 0.91; //damage done by player decreases each level
game.accelScale /= 1.027 //mob acceleration increases each level
game.lookFreqScale /= 0.974 //mob cycles between looks decreases each level
game.CDScale /= 0.964 //mob CD time decreases each level
}
if (game.difficulty < 1) game.difficulty = 0;
game.healScale = 1 / (1 + game.difficulty * 0.09)
},
difficultyText(mode = document.getElementById("difficulty-select").value) {
if (mode === "0") {
return "easy"
} else if (mode === "1") {
return "normal"
} else if (mode === "2") {
return "hard"
} else if (mode === "4") {
return "why"
}
},
levelAnnounce() {
if (level.levelsCleared === 0) {
document.title = "n-gon: intro (" + level.difficultyText() + ")";
} else {
document.title = "n-gon: L" + (level.levelsCleared) + " " + level.levels[level.onLevel] + " (" + level.difficultyText() + ")";
}
},
custom() {}, //each level runs it's own custom code (level exits, ...)
nextLevel() {
level.levelsCleared++;
level.onLevel++; //cycles map to next level
if (level.onLevel > level.levels.length - 1) level.onLevel = 0;
level.difficultyIncrease(game.difficultyMode) //increase difficulty based on modes
if (game.isEasyMode && level.levelsCleared % 2) level.difficultyDecrease(1);
game.clearNow = true; //triggers in game.clearMap to remove all physics bodies and setup for new map
},
playerExitCheck() {
if (
player.position.x > level.exit.x &&
player.position.x < level.exit.x + 100 &&
player.position.y > level.exit.y - 150 &&
player.position.y < level.exit.y - 40 &&
player.velocity.y < 0.1
) {
level.nextLevel()
}
},
setPosToSpawn(xPos, yPos) {
mech.spawnPos.x = mech.pos.x = xPos;
mech.spawnPos.y = mech.pos.y = yPos;
level.enter.x = mech.spawnPos.x - 50;
level.enter.y = mech.spawnPos.y + 20;
mech.transX = mech.transSmoothX = canvas.width2 - mech.pos.x;
mech.transY = mech.transSmoothY = canvas.height2 - mech.pos.y;
mech.Vx = mech.spawnVel.x;
mech.Vy = mech.spawnVel.y;
player.force.x = 0;
player.force.y = 0;
Matter.Body.setPosition(player, mech.spawnPos);
Matter.Body.setVelocity(player, mech.spawnVel);
},
enter: {
x: 0,
y: 0,
draw() {
ctx.beginPath();
ctx.moveTo(level.enter.x, level.enter.y + 30);
ctx.lineTo(level.enter.x, level.enter.y - 80);
ctx.bezierCurveTo(level.enter.x, level.enter.y - 170, level.enter.x + 100, level.enter.y - 170, level.enter.x + 100, level.enter.y - 80);
ctx.lineTo(level.enter.x + 100, level.enter.y + 30);
ctx.lineTo(level.enter.x, level.enter.y + 30);
ctx.fillStyle = "#ccc";
ctx.fill();
}
},
exit: {
x: 0,
y: 0,
draw() {
ctx.beginPath();
ctx.moveTo(level.exit.x, level.exit.y + 30);
ctx.lineTo(level.exit.x, level.exit.y - 80);
ctx.bezierCurveTo(level.exit.x, level.exit.y - 170, level.exit.x + 100, level.exit.y - 170, level.exit.x + 100, level.exit.y - 80);
ctx.lineTo(level.exit.x + 100, level.exit.y + 30);
ctx.lineTo(level.exit.x, level.exit.y + 30);
ctx.fillStyle = "#0ff";
ctx.fill();
}
},
fillBG: [],
drawFillBGs() {
for (let i = 0, len = level.fillBG.length; i < len; ++i) {
const f = level.fillBG[i];
ctx.fillStyle = f.color;
ctx.fillRect(f.x, f.y, f.width, f.height);
}
},
fill: [],
drawFills() {
for (let i = 0, len = level.fill.length; i < len; ++i) {
const f = level.fill[i];
ctx.fillStyle = f.color;
ctx.fillRect(f.x, f.y, f.width, f.height);
}
},
queryList: [], //queries do actions on many objects in regions
checkQuery() {
let bounds, action, info;
function isInZone(targetArray) {
let results = Matter.Query.region(targetArray, bounds);
for (let i = 0, len = results.length; i < len; ++i) {
level.queryActions[action](results[i], info);
}
}
for (let i = 0, len = level.queryList.length; i < len; ++i) {
bounds = level.queryList[i].bounds;
action = level.queryList[i].action;
info = level.queryList[i].info;
for (let j = 0, l = level.queryList[i].groups.length; j < l; ++j) {
isInZone(level.queryList[i].groups[j]);
}
}
},
//oddly query regions can't get smaller than 50 width?
addQueryRegion(x, y, width, height, action, groups = [
[player], body, mob, powerUp, bullet
], info) {
level.queryList[level.queryList.length] = {
bounds: {
min: {
x: x,
y: y
},
max: {
x: x + width,
y: y + height
}
},
action: action,
groups: groups,
info: info
//******************************************************************************************************************
//******************************************************************************************************************
//******************************************************************************************************************
//******************************************************************************************************************
bossRoom1() {
level.custom = () => {
level.playerExitCheck();
};
},
queryActions: {
bounce(target, info) {
//jerky fling upwards
Matter.Body.setVelocity(target, {
x: info.Vx + (Math.random() - 0.5) * 6,
y: info.Vy
});
target.torque = (Math.random() - 0.5) * 2 * target.mass;
},
boost(target, yVelocity) {
// if (target.velocity.y < 0) {
// mech.undoCrouch();
// mech.enterAir();
mech.buttonCD_jump = 0; // reset short jump counter to prevent short jumps on boosts
mech.hardLandCD = 0 // disable hard landing
if (target.velocity.y > 30) {
Matter.Body.setVelocity(target, {
x: target.velocity.x + (Math.random() - 0.5) * 2,
y: -23 //gentle bounce if coming down super fast
});
} else {
Matter.Body.setVelocity(target, {
x: target.velocity.x + (Math.random() - 0.5) * 2,
y: yVelocity
});
}
level.setPosToSpawn(0, -50); //normal spawn
spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
level.exit.x = 1500;
level.exit.y = -1875;
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
// level.fill.push({ //foreground
// x: 2500,
// y: -1100,
// width: 450,
// height: 250,
// color: "rgba(0,0,0,0.1)"
// });
// level.fillBG.push({ //background
// x: 1300,
// y: -1800,
// width: 750,
// height: 1800,
// color: "#d4d4d7"
// });
},
force(target, info) {
if (target.velocity.y < 0) {
//gently force up if already on the way up
target.force.x += info.Vx * target.mass;
target.force.y += info.Vy * target.mass;
} else {
target.force.y -= 0.0007 * target.mass; //gently fall in on the way down
}
},
antiGrav(target) {
target.force.y -= 0.0011 * target.mass;
},
death(target) {
target.death();
}
spawn.mapRect(-100, 0, 1000, 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);
},
addToWorld() {
//needs to be run to put bodies into the world
for (let i = 0; i < body.length; i++) {
//body[i].collisionFilter.group = 0;
if (body[i] !== mech.holdingTarget) {
body[i].collisionFilter.category = cat.body;
body[i].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet
}
body[i].classType = "body";
World.add(engine.world, body[i]); //add to world
}
for (let i = 0; i < map.length; i++) {
//map[i].collisionFilter.group = 0;
map[i].collisionFilter.category = cat.map;
map[i].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet;
Matter.Body.setStatic(map[i], true); //make static
World.add(engine.world, map[i]); //add to world
}
for (let i = 0; i < cons.length; i++) {
World.add(engine.world, cons[i]);
}
for (let i = 0; i < consBB.length; i++) {
World.add(engine.world, consBB[i]);
}
template() {
level.custom = () => {
level.playerExitCheck();
};
level.setPosToSpawn(0, -50); //normal spawn
spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
level.exit.x = 1500;
level.exit.y = -1875;
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
// level.fill.push({ //foreground
// x: 2500,
// y: -1100,
// width: 450,
// height: 250,
// color: "rgba(0,0,0,0.1)"
// });
// level.fillBG.push({ //background
// x: 1300,
// y: -1800,
// width: 750,
// height: 1800,
// color: "#d4d4d7"
// });
spawn.mapRect(-100, 0, 1000, 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);
},
//******************************************************************************************************************
//******************************************************************************************************************
//******************************************************************************************************************
//******************************************************************************************************************
testing() {
level.custom = () => {
level.playerExitCheck();
@@ -358,14 +198,14 @@ const level = {
spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 100); //exit bump
spawn.boost(1500, 0, 900);
// spawn.bomberBoss(2900, -500)
spawn.bomberBoss(2900, -500)
// spawn.launcherBoss(1200, -500)
// spawn.laserTargetingBoss(1600, -400)
// spawn.spawner(1600, -500)
// spawn.sniper(1700, -120, 50)
spawn.sniper(1400, -120)
spawn.sniper(1800, -120)
spawn.sniper(2200, -120)
// spawn.sniper(1400, -120)
// spawn.sniper(1800, -120)
// spawn.sniper(2200, -120)
// spawn.cellBossCulture(1600, -500)
// spawn.shooter(1600, -500)
// spawn.striker(1600, -500)
@@ -2056,4 +1896,239 @@ const level = {
if (game.difficulty > 3) spawn.randomLevelBoss(1850, -1400, 1);
},
//******************************************************************************************************************
//******************************************************************************************************************
//******************************************************************************************************************
//******************************************************************************************************************
isBuildRun: false,
difficultyIncrease(num = 1) {
// if (level.isBuildRun) num++
for (let i = 0; i < num; i++) {
game.difficulty++
game.dmgScale += 0.21; //damage done by mobs increases each level
b.dmgScale *= 0.91; //damage done by player decreases each level
game.accelScale *= 1.027 //mob acceleration increases each level
game.lookFreqScale *= 0.974 //mob cycles between looks decreases each level
game.CDScale *= 0.964 //mob CD time decreases each level
}
game.healScale = 1 / (1 + game.difficulty * 0.09) //a higher denominator makes for lower heals // mech.health += heal * game.healScale;
},
difficultyDecrease(num = 1) { //used in easy mode for game.reset()
for (let i = 0; i < num; i++) {
game.difficulty--
game.dmgScale -= 0.21; //damage done by mobs increases each level
if (game.dmgScale < 0.1) game.dmgScale = 0.1;
b.dmgScale /= 0.91; //damage done by player decreases each level
game.accelScale /= 1.027 //mob acceleration increases each level
game.lookFreqScale /= 0.974 //mob cycles between looks decreases each level
game.CDScale /= 0.964 //mob CD time decreases each level
}
if (game.difficulty < 1) game.difficulty = 0;
game.healScale = 1 / (1 + game.difficulty * 0.09)
},
difficultyText(mode = document.getElementById("difficulty-select").value) {
if (mode === "0") {
return "easy"
} else if (mode === "1") {
return "normal"
} else if (mode === "2") {
return "hard"
} else if (mode === "4") {
return "why"
}
},
levelAnnounce() {
if (level.levelsCleared === 0) {
document.title = "n-gon: intro (" + level.difficultyText() + ")";
} else {
document.title = "n-gon: L" + (level.levelsCleared) + " " + level.levels[level.onLevel] + " (" + level.difficultyText() + ")";
}
},
custom() {}, //each level runs it's own custom code (level exits, ...)
nextLevel() {
level.levelsCleared++;
level.onLevel++; //cycles map to next level
if (level.onLevel > level.levels.length - 1) level.onLevel = 0;
level.difficultyIncrease(game.difficultyMode) //increase difficulty based on modes
if (game.isEasyMode && level.levelsCleared % 2) level.difficultyDecrease(1);
game.clearNow = true; //triggers in game.clearMap to remove all physics bodies and setup for new map
if (mod.isHealLowHealth && mech.health < mech.maxHealth * 0.5) {
mech.health = mech.maxHealth * 0.5
mod.onHealthChange();
mech.displayHealth();
}
},
playerExitCheck() {
if (
player.position.x > level.exit.x &&
player.position.x < level.exit.x + 100 &&
player.position.y > level.exit.y - 150 &&
player.position.y < level.exit.y - 40 &&
player.velocity.y < 0.1
) {
level.nextLevel()
}
},
setPosToSpawn(xPos, yPos) {
mech.spawnPos.x = mech.pos.x = xPos;
mech.spawnPos.y = mech.pos.y = yPos;
level.enter.x = mech.spawnPos.x - 50;
level.enter.y = mech.spawnPos.y + 20;
mech.transX = mech.transSmoothX = canvas.width2 - mech.pos.x;
mech.transY = mech.transSmoothY = canvas.height2 - mech.pos.y;
mech.Vx = mech.spawnVel.x;
mech.Vy = mech.spawnVel.y;
player.force.x = 0;
player.force.y = 0;
Matter.Body.setPosition(player, mech.spawnPos);
Matter.Body.setVelocity(player, mech.spawnVel);
},
enter: {
x: 0,
y: 0,
draw() {
ctx.beginPath();
ctx.moveTo(level.enter.x, level.enter.y + 30);
ctx.lineTo(level.enter.x, level.enter.y - 80);
ctx.bezierCurveTo(level.enter.x, level.enter.y - 170, level.enter.x + 100, level.enter.y - 170, level.enter.x + 100, level.enter.y - 80);
ctx.lineTo(level.enter.x + 100, level.enter.y + 30);
ctx.lineTo(level.enter.x, level.enter.y + 30);
ctx.fillStyle = "#ccc";
ctx.fill();
}
},
exit: {
x: 0,
y: 0,
draw() {
ctx.beginPath();
ctx.moveTo(level.exit.x, level.exit.y + 30);
ctx.lineTo(level.exit.x, level.exit.y - 80);
ctx.bezierCurveTo(level.exit.x, level.exit.y - 170, level.exit.x + 100, level.exit.y - 170, level.exit.x + 100, level.exit.y - 80);
ctx.lineTo(level.exit.x + 100, level.exit.y + 30);
ctx.lineTo(level.exit.x, level.exit.y + 30);
ctx.fillStyle = "#0ff";
ctx.fill();
}
},
fillBG: [],
drawFillBGs() {
for (let i = 0, len = level.fillBG.length; i < len; ++i) {
const f = level.fillBG[i];
ctx.fillStyle = f.color;
ctx.fillRect(f.x, f.y, f.width, f.height);
}
},
fill: [],
drawFills() {
for (let i = 0, len = level.fill.length; i < len; ++i) {
const f = level.fill[i];
ctx.fillStyle = f.color;
ctx.fillRect(f.x, f.y, f.width, f.height);
}
},
queryList: [], //queries do actions on many objects in regions
checkQuery() {
let bounds, action, info;
function isInZone(targetArray) {
let results = Matter.Query.region(targetArray, bounds);
for (let i = 0, len = results.length; i < len; ++i) {
level.queryActions[action](results[i], info);
}
}
for (let i = 0, len = level.queryList.length; i < len; ++i) {
bounds = level.queryList[i].bounds;
action = level.queryList[i].action;
info = level.queryList[i].info;
for (let j = 0, l = level.queryList[i].groups.length; j < l; ++j) {
isInZone(level.queryList[i].groups[j]);
}
}
},
//oddly query regions can't get smaller than 50 width?
addQueryRegion(x, y, width, height, action, groups = [
[player], body, mob, powerUp, bullet
], info) {
level.queryList[level.queryList.length] = {
bounds: {
min: {
x: x,
y: y
},
max: {
x: x + width,
y: y + height
}
},
action: action,
groups: groups,
info: info
};
},
queryActions: {
bounce(target, info) {
//jerky fling upwards
Matter.Body.setVelocity(target, {
x: info.Vx + (Math.random() - 0.5) * 6,
y: info.Vy
});
target.torque = (Math.random() - 0.5) * 2 * target.mass;
},
boost(target, yVelocity) {
mech.buttonCD_jump = 0; // reset short jump counter to prevent short jumps on boosts
mech.hardLandCD = 0 // disable hard landing
if (target.velocity.y > 30) {
Matter.Body.setVelocity(target, {
x: target.velocity.x + (Math.random() - 0.5) * 2,
y: -23 //gentle bounce if coming down super fast
});
} else {
Matter.Body.setVelocity(target, {
x: target.velocity.x + (Math.random() - 0.5) * 2,
y: yVelocity
});
}
},
force(target, info) {
if (target.velocity.y < 0) { //gently force up if already on the way up
target.force.x += info.Vx * target.mass;
target.force.y += info.Vy * target.mass;
} else {
target.force.y -= 0.0007 * target.mass; //gently fall in on the way down
}
},
antiGrav(target) {
target.force.y -= 0.0011 * target.mass;
},
death(target) {
target.death();
}
},
addToWorld() { //needs to be run to put bodies into the world
for (let i = 0; i < body.length; i++) {
//body[i].collisionFilter.group = 0;
if (body[i] !== mech.holdingTarget) {
body[i].collisionFilter.category = cat.body;
body[i].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet
}
body[i].classType = "body";
World.add(engine.world, body[i]); //add to world
}
for (let i = 0; i < map.length; i++) {
//map[i].collisionFilter.group = 0;
map[i].collisionFilter.category = cat.map;
map[i].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet;
Matter.Body.setStatic(map[i], true); //make static
World.add(engine.world, map[i]); //add to world
}
for (let i = 0; i < cons.length; i++) {
World.add(engine.world, cons[i]);
}
for (let i = 0; i < consBB.length; i++) {
World.add(engine.world, consBB[i]);
}
},
};

View File

@@ -44,46 +44,63 @@ const mobs = {
}
},
statusSlow(who, cycles = 60) {
if (!who.shield && !who.isShielded && !mech.isBodiesAsleep) {
if (who.isBoss) {
cycles = Math.floor(cycles * 0.25)
applySlow(who)
//look for mobs near the target
if (mod.isAoESlow) {
const range = (220 + 150 * Math.random()) ** 2
for (let i = 0, len = mob.length; i < len; i++) {
if (Vector.magnitudeSquared(Vector.sub(who.position, mob[i].position)) < range) applySlow(mob[i])
}
//remove other "slow" effects on this mob
let i = who.status.length
while (i--) {
if (who.status[i].type === "slow") who.status.splice(i, 1);
game.drawList.push({
x: who.position.x,
y: who.position.y,
radius: Math.sqrt(range),
color: "rgba(0,100,255,0.05)",
time: 3
});
}
function applySlow(target) {
if (!target.shield && !target.isShielded && !mech.isBodiesAsleep) {
if (target.isBoss) cycles = Math.floor(cycles * 0.25)
let i = target.status.length
while (i--) {
if (target.status[i].type === "slow") target.status.splice(i, 1); //remove other "slow" effects on this mob
}
target.status.push({
effect() {
Matter.Body.setVelocity(target, {
x: 0,
y: 0
});
Matter.Body.setAngularVelocity(target, 0);
ctx.beginPath();
ctx.moveTo(target.vertices[0].x, target.vertices[0].y);
for (let j = 1, len = target.vertices.length; j < len; ++j) {
ctx.lineTo(target.vertices[j].x, target.vertices[j].y);
}
ctx.lineTo(target.vertices[0].x, target.vertices[0].y);
ctx.strokeStyle = "rgba(0,100,255,0.8)";
ctx.lineWidth = 15;
ctx.stroke();
ctx.fillStyle = target.fill
ctx.fill();
},
type: "slow",
endCycle: game.cycle + cycles,
})
}
who.status.push({
effect() {
Matter.Body.setVelocity(who, {
x: 0,
y: 0
});
Matter.Body.setAngularVelocity(who, 0);
ctx.beginPath();
ctx.moveTo(who.vertices[0].x, who.vertices[0].y);
for (let j = 1, len = who.vertices.length; j < len; ++j) {
ctx.lineTo(who.vertices[j].x, who.vertices[j].y);
}
ctx.lineTo(who.vertices[0].x, who.vertices[0].y);
ctx.strokeStyle = "rgba(0,100,255,0.8)";
ctx.lineWidth = 15;
ctx.stroke();
ctx.fillStyle = who.fill
ctx.fill();
},
type: "slow",
endCycle: game.cycle + cycles,
})
}
},
statusStun(who, cycles = 180) {
if (!who.shield && !who.isShielded && !mech.isBodiesAsleep) {
Matter.Body.setVelocity(who, {
x: who.velocity.x * 0.5,
y: who.velocity.y * 0.5
x: who.velocity.x * 0.8,
y: who.velocity.y * 0.8
});
Matter.Body.setAngularVelocity(who, who.angularVelocity * 0.5);
Matter.Body.setAngularVelocity(who, who.angularVelocity * 0.8);
//remove other "stun" effects on this mob
let i = who.status.length
while (i--) {
@@ -97,7 +114,7 @@ const mobs = {
x: who.position.x + 100 * (Math.random() - 0.5),
y: who.position.y + 100 * (Math.random() - 0.5)
}
if (who.velocity.y < 2) who.force.y += who.mass * 0.0005 //extra gravity
if (who.velocity.y < 2) who.force.y += who.mass * 0.0004 //extra gravity
ctx.beginPath();
ctx.moveTo(who.vertices[0].x, who.vertices[0].y);
for (let j = 1, len = who.vertices.length; j < len; ++j) {
@@ -831,7 +848,7 @@ const mobs = {
Matter.Query.ray(map, this.position, this.mechPosRange()).length === 0 && //see player
Matter.Query.ray(body, this.position, this.mechPosRange()).length === 0
) {
spawn.bullet(this.position.x, this.position.y + this.radius * 0.5, 10 + Math.ceil(this.radius / 15), 5);
spawn.bomb(this.position.x, this.position.y + this.radius * 0.5, 10 + Math.ceil(this.radius / 15), 5);
//add spin and speed
Matter.Body.setAngularVelocity(mob[mob.length - 1], (Math.random() - 0.5) * 0.5);
Matter.Body.setVelocity(mob[mob.length - 1], {
@@ -1000,7 +1017,7 @@ const mobs = {
}
}
if (Math.random() < mod.isBotSpawner) {
if (Math.random() < 0.2) { //very low chance of plasma bot
if (Math.random() < 0.1) { //very low chance of plasma bot
b.plasmaBot(this.position)
} else if (Math.random() < 0.25) {
b.nailBot(this.position)

View File

@@ -80,36 +80,24 @@ const mod = {
return dmg * mod.slowFire
},
onHealthChange() { //used with acid mod
if (mod.isAcidDmg && mech.health > 0.8) {
mod.acidDmg = 0.5
if (!build.isCustomSelection) {
setTimeout(function () {
if (document.getElementById("mod-acid")) document.getElementById("mod-acid").innerHTML = " (on)"
}, 10);
}
} else {
mod.acidDmg = 0
if (!build.isCustomSelection) {
setTimeout(function () {
if (document.getElementById("mod-acid")) document.getElementById("mod-acid").innerHTML = " (off)"
}, 10);
if (mod.isAcidDmg) {
if (mech.health > 0.8) {
mod.acidDmg = 0.5
if (!build.isCustomSelection) {
setTimeout(function () {
if (document.getElementById("mod-acid")) document.getElementById("mod-acid").innerHTML = " (on)"
}, 10);
}
} else {
mod.acidDmg = 0
if (!build.isCustomSelection) {
setTimeout(function () {
if (document.getElementById("mod-acid")) document.getElementById("mod-acid").innerHTML = " (off)"
}, 10);
}
}
}
// if (mod.isLowHealthDmg) {
// if (!build.isCustomSelection) {
// setTimeout(function () {
// if (document.getElementById("mod-low-health-damage")) document.getElementById("mod-low-health-damage").innerHTML = " +" + (((3 / (2 + Math.min(mech.health, 1))) - 1) * 100).toFixed(0) + "%"
// }, 10);
// }
// }
},
resetModText() {
setTimeout(function () {
if (document.getElementById("mod-acid")) document.getElementById("mod-acid").innerHTML = "";
if (document.getElementById("mod-low-health-damage")) document.getElementById("mod-low-health-damage").innerHTML = "";
}, 10);
},
mods: [{
name: "capacitor",
// nameInfo: "<span id='mod-capacitor'></span>",
@@ -178,7 +166,6 @@ const mod = {
},
{
name: "negative feedback",
// nameInfo: "<span id='mod-low-health-damage'></span>",
description: "do extra <strong class='color-d'>damage</strong> at <strong>low health</strong><br><em>up to <strong>50%</strong> increase when near death</em>",
maxCount: 1,
count: 0,
@@ -587,7 +574,7 @@ const mod = {
},
{
name: "Pauli exclusion",
description: `<strong>immune</strong> to <strong>harm</strong> for <strong>1</strong> second<br>activates after being <strong>harmed</strong> from a collision`,
description: `after being <strong>harmed</strong> from a collision<br><strong>immune</strong> to <strong>harm</strong> for <strong>1</strong> second`,
maxCount: 9,
count: 0,
allowed() {
@@ -621,6 +608,11 @@ const mod = {
{
name: "entanglement",
nameInfo: "<span id = 'mod-entanglement'></span>",
addNameInfo() {
setTimeout(function () {
game.boldActiveGunHUD();
}, 1000);
},
description: "<strong>16%</strong> less <strong>harm</strong> for each gun in your <strong>inventory</strong><br> while your <strong>first gun</strong> is equipped",
maxCount: 1,
count: 0,
@@ -769,7 +761,7 @@ const mod = {
},
{
name: "negentropy",
description: "when below <strong>25%</strong> of <strong>maximum health</strong><br> <strong class='color-h'>heal</strong> <strong>1%</strong> of <strong>maximum health</strong> per second",
description: "at the start of each <strong>level</strong><br><strong class='color-h'>heal</strong> up to <strong>50%</strong> of <strong>maximum health</strong>",
maxCount: 9,
count: 0,
allowed() {
@@ -785,7 +777,7 @@ const mod = {
},
{
name: "crystallized armor",
description: "increase <strong>maximum</strong> <strong class='color-h'>health</strong> by <strong>4%</strong> for each<br>unused <strong>power up</strong> at the end of a <strong>level</strong>",
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>",
maxCount: 1,
count: 0,
allowed() {
@@ -815,23 +807,6 @@ const mod = {
mod.recursiveHealing = 1;
}
},
{
name: "pair production",
description: "<strong>power ups</strong> overfill your <strong class='color-f'>energy</strong><br>temporarily gain <strong>twice</strong> your max <strong class='color-f'>energy</strong>",
maxCount: 1,
count: 0,
allowed() {
return true
},
requires: "",
effect: () => {
mod.isMassEnergy = true // used in mech.grabPowerUp
mech.energy = mech.maxEnergy * 2
},
remove() {
mod.isMassEnergy = false;
}
},
{
name: "bubble fusion",
description: "after destroying a mob's <strong>shield</strong><br>spawn <strong>3</strong> <strong class='color-h'>heals</strong>, <strong>ammo</strong>, or <strong class='color-r'>rerolls</strong>",
@@ -886,7 +861,7 @@ const mod = {
},
{
name: "supply chain",
description: "double your current <strong>ammo</strong> for all <strong>gun</strong>",
description: "double your current <strong>ammo</strong> for all <strong>guns</strong>",
maxCount: 9,
count: 0,
isNonRefundable: true,
@@ -936,7 +911,7 @@ const mod = {
},
{
name: "cardinality",
description: "<strong>2</strong> extra <strong>choices</strong> when selecting <strong>power ups</strong>",
description: "<strong>2</strong> extra <strong>choices</strong> for <strong class='color-m'>mods</strong>, <strong>guns</strong>, and <strong>fields</strong>",
maxCount: 1,
count: 0,
allowed() {
@@ -994,7 +969,7 @@ const mod = {
},
{
name: "many-worlds",
description: "after choosing a <strong>gun</strong>, <strong>field</strong>, or <strong class='color-m'>mod</strong><br>spawn a <strong class='color-r'>reroll</strong>, if you have none",
description: "after choosing a <strong class='color-m'>mod</strong>, <strong>gun</strong>, or <strong>field</strong><br>spawn a <strong class='color-r'>reroll</strong>, if you have none",
maxCount: 1,
count: 0,
allowed() {
@@ -1011,7 +986,12 @@ const mod = {
{
name: "anthropic principle",
nameInfo: "<span id = 'mod-anthropic'></span>",
description: "<strong class='color-h'>heal</strong> to <strong>50%</strong> health instead of <strong>dying</strong><br>consumes <strong>1</strong> <strong class='color-r'>reroll</strong>",
addNameInfo() {
setTimeout(function () {
powerUps.reroll.changeRerolls(0)
}, 1000);
},
description: "<strong class='color-h'>heal</strong> to <strong>60%</strong> health instead of <strong>dying</strong><br>consumes <strong>1</strong> <strong class='color-r'>reroll</strong>",
maxCount: 1,
count: 0,
allowed() {
@@ -1030,7 +1010,7 @@ const mod = {
},
{
name: "quantum immortality",
description: "after <strong>dying</strong>, continue in an <strong>alternate reality</strong><br>spawn <strong>3</strong> <strong class='color-r'>rerolls</strong>",
description: "after <strong>dying</strong>, continue in an <strong>alternate reality</strong><br>spawn <strong>5</strong> <strong class='color-r'>rerolls</strong>",
maxCount: 1,
count: 0,
allowed() {
@@ -1039,9 +1019,9 @@ const mod = {
requires: "",
effect() {
mod.isImmortal = true;
powerUps.spawn(mech.pos.x, mech.pos.y, "reroll", false);
powerUps.spawn(mech.pos.x, mech.pos.y, "reroll", false);
powerUps.spawn(mech.pos.x, mech.pos.y, "reroll", false);
for (let i = 0; i < 5; i++) {
powerUps.spawn(mech.pos.x, mech.pos.y, "reroll", false);
}
},
remove() {
mod.isImmortal = false;
@@ -1143,6 +1123,9 @@ const mod = {
{
name: "fluoroantimonic acid",
nameInfo: "<span id='mod-acid'></span>",
addNameInfo() {
mod.onHealthChange();
},
description: "each <strong>bullet</strong> does instant <strong class='color-p'>acid</strong> <strong class='color-d'>damage</strong><br><strong>active</strong> when you are above <strong>80%</strong> base health",
maxCount: 1,
count: 0,
@@ -1153,7 +1136,6 @@ const mod = {
requires: "health above 80%",
effect() {
mod.isAcidDmg = true;
mod.onHealthChange();
},
remove() {
mod.acidDmg = 0;
@@ -1697,6 +1679,22 @@ const mod = {
mod.isFastDrones = false
}
},
{
name: "superfluidity",
description: "<strong class='color-s'>freeze</strong> effects apply to mobs near it's target",
maxCount: 1,
count: 0,
allowed() {
return mod.haveGunCheck("ice IX") || mod.isIceCrystals || mod.isSporeFreeze || (mech.fieldUpgrades[mech.fieldMode].name === "nano-scale manufacturing" && mod.isIceField)
},
requires: "a freeze effect",
effect() {
mod.isAoESlow = true
},
remove() {
mod.isAoESlow = false
}
},
{
name: "heavy water",
description: "<strong>ice IX</strong> is synthesized with an extra neutron<br>does <strong class='color-p'>radioactive</strong> <strong class='color-d'>damage</strong> over 3 seconds",
@@ -1991,6 +1989,23 @@ const mod = {
mech.fieldShieldingScale = 1;
}
},
{
name: "pair production",
description: "<strong>power ups</strong> overfill your <strong class='color-f'>energy</strong><br>temporarily gain <strong>3x</strong> your maximum <strong class='color-f'>energy</strong>",
maxCount: 1,
count: 0,
allowed() {
return mech.fieldUpgrades[mech.fieldMode].name === "nano-scale manufacturing"
},
requires: "nano-scale manufacturing",
effect: () => {
mod.isMassEnergy = true // used in mech.grabPowerUp
mech.energy = mech.maxEnergy * 3
},
remove() {
mod.isMassEnergy = false;
}
},
{
name: "mycelium manufacturing",
description: "<strong>nano-scale manufacturing</strong> is repurposed<br>excess <strong class='color-f'>energy</strong> used to grow <strong class='color-p' style='letter-spacing: 2px;'>spores</strong>",
@@ -2276,5 +2291,6 @@ const mod = {
isPulseAim: null,
isSporeFreeze: null,
isShotgunRecoil: null,
isHealLowHealth: null
isHealLowHealth: null,
isAoESlow: null
}

View File

@@ -476,7 +476,7 @@ const mech = {
if (mod.isDeathAvoid && powerUps.reroll.rerolls) { //&& Math.random() < 0.5
powerUps.reroll.changeRerolls(-1)
mech.energy = mech.maxEnergy * 0.5
mech.energy = mech.maxEnergy * 0.6
// if (mech.energy < 0.05) mech.energy = 0.05
mech.immuneCycle = mech.cycle + 120 //disable this.immuneCycle bonus seconds
game.makeTextLog("<span style='font-size:115%;'> <strong>death</strong> avoided<br><strong>1</strong> <strong class='color-r'>reroll</strong> consumed</span>", 420)
@@ -505,7 +505,7 @@ const mech = {
if (mech.health < 0 || isNaN(mech.health)) {
if (mod.isDeathAvoid && powerUps.reroll.rerolls > 0) { //&& Math.random() < 0.5
powerUps.reroll.changeRerolls(-1)
mech.health = mech.maxHealth * 0.5
mech.health = mech.maxHealth * 0.6
// if (mech.health < 0.05) mech.health = 0.05
mech.immuneCycle = mech.cycle + 120 //disable this.immuneCycle bonus seconds
game.makeTextLog("<span style='font-size:115%;'> <strong>death</strong> avoided<br><strong>1</strong> <strong class='color-r'>reroll</strong> consumed</span>", 420)
@@ -942,7 +942,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 * 2;
if (mod.isMassEnergy) mech.energy = mech.maxEnergy * 3;
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
@@ -1950,7 +1950,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 * 2;
if (mod.isMassEnergy) mech.energy = mech.maxEnergy * 3;
powerUp[i].effect();
Matter.World.remove(engine.world, powerUp[i]);
powerUp.splice(i, 1);

View File

@@ -79,7 +79,7 @@ const powerUps = {
}
return out
},
use(type) {
use(type) { //runs when you actually reroll a list of selections, type can be field, gun, or mod
powerUps.reroll.changeRerolls(-1)
powerUps[type].effect();
},
@@ -218,7 +218,6 @@ const powerUps = {
choiceLog: [], //records all previous choice options
effect() {
function pick(skip1 = -1, skip2 = -1, skip3 = -1, skip4 = -1) {
let options = [];
for (let i = 0; i < mod.mods.length; i++) {

View File

@@ -1466,20 +1466,20 @@ const spawn = {
// }
// };
// },
bomberBoss(x, y, radius = 85 + Math.ceil(Math.random() * 20)) {
bomberBoss(x, y, radius = 80 + Math.floor(Math.random() * 15)) {
//boss that drops bombs from above and holds a set distance from player
mobs.spawn(x, y, 3, radius, "transparent");
let me = mob[mob.length - 1];
me.isBoss = true;
Matter.Body.setDensity(me, 0.0015 + 0.0004 * Math.sqrt(game.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
Matter.Body.setDensity(me, 0.0014 + 0.0003 * Math.sqrt(game.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
me.stroke = "rgba(255,0,200)"; //used for drawGhost
me.seeAtDistance2 = 1500000;
me.fireFreq = Math.ceil(30 + 2000 / radius);
me.fireFreq = Math.ceil(60 + 3000 / radius);
me.searchTarget = map[Math.floor(Math.random() * (map.length - 1))].position; //required for search
me.hoverElevation = 460 + (Math.random() - 0.5) * 200; //squared
me.hoverXOff = (Math.random() - 0.5) * 100;
me.accelMag = Math.floor(10 * (Math.random() + 5)) * 0.00001 * game.accelScale;
me.accelMag = Math.floor(10 * (Math.random() + 4.5)) * 0.00001 * game.accelScale;
me.g = 0.0002; //required if using 'gravity' // gravity called in hoverOverPlayer
me.frictionStatic = 0;
me.friction = 0;
@@ -1578,7 +1578,7 @@ const spawn = {
this.explode(this.mass * 10);
};
Matter.Body.setDensity(me, 0.0001); //normal is 0.001
me.timeLeft = 240;
me.timeLeft = 200;
me.g = 0.001; //required if using 'gravity'
me.frictionAir = 0;
me.restitution = 0.8;
@@ -1592,6 +1592,58 @@ const spawn = {
this.timeLimit();
};
},
bomb(x, y, radius = 6, sides = 5) {
mobs.spawn(x, y, sides, radius, "rgb(255,0,0)");
let me = mob[mob.length - 1];
me.stroke = "transparent";
me.onHit = function () {
this.explode(this.mass * 10);
};
me.onDeath = function () {
if (game.difficulty > 10) {
spawn.bullet(this.position.x, this.position.y, this.radius / 3, 5);
spawn.bullet(this.position.x, this.position.y, this.radius / 3, 5);
spawn.bullet(this.position.x, this.position.y, this.radius / 3, 5);
const mag = 8
const v1 = Vector.rotate({
x: 1,
y: 1
}, 2 * Math.PI * Math.random())
const v2 = Vector.rotate({
x: 1,
y: 1
}, 2 * Math.PI * Math.random())
const v3 = Vector.normalise(Vector.add(v1, v2)) //last vector is opposite the sum of the other two to look a bit like momentum is conserved
Matter.Body.setVelocity(mob[mob.length - 1], {
x: mag * v1.x,
y: mag * v1.y
});
Matter.Body.setVelocity(mob[mob.length - 2], {
x: mag * v2.x,
y: mag * v2.y
});
Matter.Body.setVelocity(mob[mob.length - 3], {
x: -mag * v3.x,
y: -mag * v3.y
});
}
}
Matter.Body.setDensity(me, 0.0001); //normal is 0.001
me.timeLeft = 95 + Math.floor(Math.random() * 15);
me.g = 0.001; //required if using 'gravity'
me.frictionAir = 0;
me.restitution = 1;
me.leaveBody = false;
me.dropPowerUp = false;
me.showHealthBar = false;
me.collisionFilter.category = cat.mobBullet;
me.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet;
me.do = function () {
this.gravity();
this.timeLimit();
};
},
sniper(x, y, radius = 35 + Math.ceil(Math.random() * 30)) {
mobs.spawn(x, y, 3, radius, "transparent"); //"rgb(25,0,50)")