seePlayerByHistory

blinkBoss - teleports after you, drops grenades after each teleport
sneaker (the stealthy black pentagons) - decloaks slower, moves slower, is smaller, has more health

some mobs can now sense you by "smelling" where you were
  they check for a clear line of sight with your last 10 seconds of history
  snakeBoss, blinkBoss, sneaker

extra bosses no longer spawn on final level
beating the final boss clears mobs that spawn after a mob dies, like powerUpBoss

phonon and isotropic radiator range reduced about 10%
This commit is contained in:
landgreen
2021-07-27 19:52:01 -07:00
parent 3977b44ec7
commit 030824ed5d
9 changed files with 249 additions and 156 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@@ -3205,7 +3205,7 @@ const b = {
range: (700 + 400 * tech.isLaserBotUpgrade) * (1 + 0.1 * Math.random()),
drainThreshold: tech.isEnergyHealth ? 0.6 : 0.4,
drain: (0.56 - 0.42 * tech.isLaserBotUpgrade) * tech.laserFieldDrain * tech.isLaserDiode,
laserDamage: 0.6 + 0.43 * tech.isLaserBotUpgrade,
laserDamage: 0.7 + 0.5 * tech.isLaserBotUpgrade,
endCycle: Infinity,
classType: "bullet",
collisionFilter: {
@@ -3916,21 +3916,21 @@ const b = {
}
}
} else if (tech.isWormShot) {
const unit = {
x: Math.cos(m.angle),
y: Math.sin(m.angle)
}
const where = {
x: m.pos.x + 35 * unit.x,
y: m.pos.y + 35 * unit.y
x: m.pos.x + 35 * Math.cos(m.angle),
y: m.pos.y + 35 * Math.sin(m.angle)
}
for (let i = 0, len = 3 * (tech.isShotgunReversed ? 1.6 : 1) + Math.random(); i < len; i++) {
const spread = (m.crouch ? 0.04 : 0.08)
const number = 3 * (tech.isShotgunReversed ? 1.6 : 1) + Math.random()
let angle = m.angle - (number - 1) * spread * 0.5
for (let i = 0; i < number; i++) {
b.worm(where)
const SPEED = 14 + 6 * Math.random() + 20 * m.crouch;
const SPEED = (16 + 20 * m.crouch) * (1 + 0.15 * Math.random())
Matter.Body.setVelocity(bullet[bullet.length - 1], {
x: SPEED * unit.x,
y: SPEED * unit.y
x: SPEED * Math.cos(angle),
y: SPEED * Math.sin(angle)
});
angle += spread
}
} else if (tech.isIceShot) {
const spread = (m.crouch ? 0.7 : 1.2)
@@ -4131,7 +4131,7 @@ const b = {
ctx.strokeStyle = "rgba(0,0,0,0.6)" //"000";
ctx.lineWidth = 2 * tech.wavePacketDamage
ctx.beginPath();
const end = 750 * Math.sqrt(tech.isBulletsLastLonger) / Math.sqrt(tech.waveReflections * 0.5) //should equal about 1060
const end = 700 * Math.sqrt(tech.isBulletsLastLonger) / Math.sqrt(tech.waveReflections * 0.5) //should equal about 1060
const damage = 2 * b.dmgScale * tech.wavePacketDamage * tech.waveBeamDamage //damage is lower for large radius mobs, since they feel the waves longer
for (let i = this.waves.length - 1; i > -1; i--) {
@@ -4213,7 +4213,7 @@ const b = {
ctx.strokeStyle = "rgba(0,0,0,0.6)" //"000";
ctx.lineWidth = 2 * tech.wavePacketDamage
ctx.beginPath();
const end = 1250 * tech.isBulletsLastLonger / Math.sqrt(tech.waveReflections * 0.5) //should equal about 1767
const end = 1100 * tech.isBulletsLastLonger / Math.sqrt(tech.waveReflections * 0.5) //should equal about 1767
const damage = 2 * b.dmgScale * tech.wavePacketDamage * tech.waveBeamDamage //damage is lower for large radius mobs, since they feel the waves longer
for (let i = this.waves.length - 1; i > -1; i--) {

View File

@@ -30,11 +30,11 @@ function shuffle(array) {
return array;
}
// shrink power up selection menu to find window height
if (screen.height < 800) {
document.getElementById("choose-grid").style.fontSize = "1em"; //1.3em is normal
if (screen.height < 600) document.getElementById("choose-grid").style.fontSize = "0.8em"; //1.3em is normal
}
// shrink power up selection menu
// if (screen.height < 800) {
// document.getElementById("choose-grid").style.fontSize = "1em"; //1.3em is normal
// if (screen.height < 600) document.getElementById("choose-grid").style.fontSize = "0.8em"; //1.3em is normal
// }
//**********************************************************************

View File

@@ -16,7 +16,6 @@ const level = {
// simulation.isHorizontalFlipped = true
// m.setField("wormhole")
// b.giveGuns("shotgun")
// b.giveGuns("foam")
// tech.isNeedleShot = true
// tech.isIceShot = true
// tech.isFoamShot = true
@@ -2264,15 +2263,21 @@ const level = {
spawn.mapRect(6400, -200, 400, 300); //right wall
spawn.mapRect(6700, -1800, 800, 2600); //right wall
spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 100); //exit bump
spawn.starter(1900, -500, 200) //big boy
//place to hide
spawn.mapRect(4650, -300, 1150, 50);
spawn.mapRect(5750, -300, 50, 200);
spawn.mapRect(5575, -100, 50, 125);
spawn.mapRect(5300, -275, 50, 175);
spawn.mapRect(5050, -100, 50, 150);
spawn.mapRect(4850, -275, 50, 175);
// spawn.starter(1900, -500, 200) //big boy
// spawn.growBossCulture(1900, -500)
// spawn.blinkBoss(1900, -500)
// spawn.snakeBoss(1900, -500)
// spawn.shieldingBoss(1900, -500)
// spawn.grenadierBoss(1900, -500)
// spawn.shieldingBoss(1900, -500)
spawn.sneaker(1900, -500)
// spawn.historyBoss(1200, -500)
// spawn.laserTargetingBoss(1600, -400)
// spawn.focuser(1600, -500)
@@ -2327,6 +2332,8 @@ const level = {
ctx.fillRect(5400, -550, 300, 350)
};
spawn.powerUpBoss(0, 0)
spawn.powerUpBoss(0, 0)
level.setPosToSpawn(0, -250); //normal spawn
spawn.mapRect(5500, -330 + 20, 100, 20); //spawn this because the real exit is in the wrong spot
spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
@@ -2364,7 +2371,7 @@ const level = {
spawn.mapRect(5700, -3300, 1800, 5100); //right wall
spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 100); //exit bump
spawn.mapRect(5425, -650, 375, 450); //blocking exit
spawn.secondaryBossChance(4800, -500)
// spawn.secondaryBossChance(4800, -500) //no bonus bosses on final level
if (simulation.isHorizontalFlipped) { //flip the map horizontally
level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit
@@ -3229,7 +3236,7 @@ const level = {
spawn.randomGroup(1600, -100, 0);
spawn.randomGroup(5000, -3900, -0.3);
if (simulation.difficulty > 3) {
if (Math.random() < 0.2) {
if (Math.random() < 0.25) {
spawn.randomLevelBoss(2800, -1400);
} else if (Math.random() < 0.25) {
spawn.laserBoss(2900 + 300 * Math.random(), -2950 + 150 * Math.random());
@@ -3606,7 +3613,7 @@ const level = {
spawn.randomMob(3975, -3900, 0.5);
spawn.randomMob(1725, 125, 0.5);
if (simulation.difficulty > 3) {
if (Math.random() < 0.25) {
if (Math.random() < 0.33) {
spawn.randomLevelBoss(4250, -250);
spawn.debris(-250, 50, 1650, 2); //16 debris per level
spawn.debris(2475, 0, 750, 2); //16 debris per level
@@ -4349,7 +4356,7 @@ const level = {
spawn.randomSmallMob(-900, 825);
if (simulation.difficulty > 3) {
if (Math.random() < 0.25) {
if (Math.random() < 0.33) {
spawn.randomLevelBoss(-800, -1300)
} else {
spawn.snakeBoss(-1000 + Math.random() * 2500, -1300); //boss snake with head

View File

@@ -284,7 +284,7 @@ const mobs = {
},
memory: 120, //default time to remember player's location
locatePlayer() { // updates mob's memory of player location
this.seePlayer.recall = this.memory + Math.round(this.memory * Math.random()); //seconds before mob falls a sleep
this.seePlayer.recall = this.memory + Math.round(this.memory * Math.random()); //cycles before mob falls a sleep
this.seePlayer.position.x = player.position.x;
this.seePlayer.position.y = player.position.y;
},
@@ -309,12 +309,38 @@ const mobs = {
// this.seePlayer.position.y = player.position.y;
// }
// },
seePlayerByHistory(depth = 30) { //depth max 60? limit of history
if (!(simulation.cycle % this.seePlayerFreq)) {
if (Matter.Query.ray(map, this.position, this.playerPosRandomY()).length === 0 && !m.isCloak) {
this.foundPlayer();
} else if (this.seePlayer.recall) {
this.lostPlayer();
for (let i = 0; i < depth; i++) { //if lost player lock onto a player location in history
let history = m.history[(m.cycle - 10 * i) % 600]
if (Matter.Query.ray(map, this.position, history.position).length === 0) {
this.seePlayer.recall = this.memory + Math.round(this.memory * Math.random()); //cycles before mob falls a sleep
this.seePlayer.position.x = history.position.x;
this.seePlayer.position.y = history.position.y;
this.seePlayer.yes = true;
//draw the history location found for testing purposes
// ctx.beginPath();
// ctx.moveTo(this.position.x, this.position.y);
// ctx.lineTo(history.position.x, history.position.y);
// ctx.lineWidth = 5;
// ctx.strokeStyle = "#000";
// ctx.stroke();
break
}
}
}
}
},
seePlayerCheck() {
if (!(simulation.cycle % this.seePlayerFreq)) {
if (
this.distanceToPlayer2() < this.seeAtDistance2 &&
Matter.Query.ray(map, this.position, this.mPosRange()).length === 0 &&
// Matter.Query.ray(body, this.position, this.mPosRange()).length === 0 &&
Matter.Query.ray(map, this.position, this.playerPosRandomY()).length === 0 &&
// Matter.Query.ray(body, this.position, this.playerPosRandomY()).length === 0 &&
!m.isCloak
) {
this.foundPlayer();
@@ -335,7 +361,7 @@ const mobs = {
seePlayerByDistOrLOS() {
if (!(simulation.cycle % this.seePlayerFreq)) {
if (
(this.distanceToPlayer2() < this.seeAtDistance2 || (Matter.Query.ray(map, this.position, this.mPosRange()).length === 0 && Matter.Query.ray(body, this.position, this.mPosRange()).length === 0)) &&
(this.distanceToPlayer2() < this.seeAtDistance2 || (Matter.Query.ray(map, this.position, this.playerPosRandomY()).length === 0 && Matter.Query.ray(body, this.position, this.playerPosRandomY()).length === 0)) &&
!m.isCloak
) {
this.foundPlayer();
@@ -366,8 +392,8 @@ const mobs = {
if (!(simulation.cycle % this.seePlayerFreq) && (this.seePlayer.recall || this.isLookingAtPlayer(this.lookRange))) {
if (
this.distanceToPlayer2() < this.seeAtDistance2 &&
Matter.Query.ray(map, this.position, this.mPosRange()).length === 0 &&
// Matter.Query.ray(body, this.position, this.mPosRange()).length === 0 &&
Matter.Query.ray(map, this.position, this.playerPosRandomY()).length === 0 &&
// Matter.Query.ray(body, this.position, this.playerPosRandomY()).length === 0 &&
!m.isCloak
) {
this.foundPlayer();
@@ -387,7 +413,7 @@ const mobs = {
ctx.fill();
}
},
mPosRange() {
playerPosRandomY() {
return {
x: player.position.x, // + (Math.random() - 0.5) * 50,
y: player.position.y + (Math.random() - 0.5) * 110
@@ -412,7 +438,7 @@ const mobs = {
// this.force = Vector.mult(Vector.normalise(Vector.sub(this.hackedTarget.position, this.position)), this.mass * 0.0015)
// }
// },
laserBeam() {
harmZone() {
if (this.seePlayer.yes) {
ctx.setLineDash([125 * Math.random(), 125 * Math.random()]);
// ctx.lineDashOffset = 6*(simulation.cycle % 215);
@@ -879,8 +905,8 @@ const mobs = {
if (
!(simulation.cycle % this.fireFreq) &&
Math.abs(this.position.x - this.seePlayer.position.x) < 400 && //above player
Matter.Query.ray(map, this.position, this.mPosRange()).length === 0 && //see player
Matter.Query.ray(body, this.position, this.mPosRange()).length === 0
Matter.Query.ray(map, this.position, this.playerPosRandomY()).length === 0 && //see player
Matter.Query.ray(body, this.position, this.playerPosRandomY()).length === 0
) {
spawn.bomb(this.position.x, this.position.y + this.radius * 0.7, 9 + Math.ceil(this.radius / 15), 5);
//add spin and speed

View File

@@ -1462,7 +1462,8 @@ const m = {
},
fieldUpgrades: [{
name: "field emitter",
description: "use <strong class='color-f'>energy</strong> to <strong>deflect</strong> mobs,<br><strong>grab</strong> power ups, and <strong>throw</strong> <strong class='color-block'>blocks</strong><br>regen <strong>6</strong> <strong class='color-f'>energy</strong> per second",
description: "regen <strong>6</strong> <strong class='color-f'>energy</strong> per second<br>use it to <strong>deflect</strong> mobs and <strong>throw</strong> <strong class='color-block'>blocks</strong><br><strong class='color-f'>energy</strong> regen disabled if immune to <strong class='color-harm'>harm</strong>",
// description: "use <strong class='color-f'>energy</strong> to <strong>deflect</strong> mobs,<br><strong>grab</strong> power ups, and <strong>throw</strong> <strong class='color-block'>blocks</strong><br>regen <strong>6</strong> <strong class='color-f'>energy</strong>/s, when not immune to <strong class='color-harm'>harm</strong>",
effect: () => {
m.hold = function() {
if (m.isHolding) {

View File

@@ -1,7 +1,7 @@
//main object for spawning things in a level
const spawn = {
nonCollideBossList: ["cellBossCulture", "bomberBoss", "powerUpBoss", "orbitalBoss", "spawnerBossCulture", "growBossCulture"],
randomLevelBoss(x, y, options = ["shieldingBoss", "orbitalBoss", "historyBoss", "shooterBoss", "cellBossCulture", "bomberBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss", "powerUpBoss", "snakeBoss", "streamBoss", "pulsarBoss", "spawnerBossCulture", "grenadierBoss", "growBossCulture"]) {
randomLevelBoss(x, y, options = ["shieldingBoss", "orbitalBoss", "historyBoss", "shooterBoss", "cellBossCulture", "bomberBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss", "powerUpBoss", "snakeBoss", "streamBoss", "pulsarBoss", "spawnerBossCulture", "grenadierBoss", "growBossCulture", "blinkBoss"]) {
// other bosses: suckerBoss, laserBoss, tetherBoss, //these need a particular level to work so they are not included in the random pool
spawn[options[Math.floor(Math.random() * options.length)]](x, y)
},
@@ -17,8 +17,8 @@ const spawn = {
"launcher", "launcher",
"springer", "springer",
"pulsar", "pulsar",
"sneaker", "sneaker",
"sucker",
"chaser",
"sniper",
"spinner",
"grower",
@@ -26,9 +26,8 @@ const spawn = {
"focuser",
"spawner",
"ghoster",
"sneaker",
],
allowedGroupList: ["chaser", "spinner", "striker", "springer", "laser", "focuser", "beamer", "exploder", "spawner", "shooter", "launcher", "stabber", "sniper", "pulsar", "grenadier"],
allowedGroupList: ["spinner", "striker", "springer", "laser", "focuser", "beamer", "exploder", "spawner", "shooter", "launcher", "stabber", "sniper", "pulsar", "grenadier"],
setSpawnList() { //this is run at the start of each new level to determine the possible mobs for the level
//each level has 2 mobs: one new mob and one from the last level
spawn.pickList.splice(0, 1);
@@ -366,8 +365,10 @@ const spawn = {
Matter.Body.setVelocity(body[i], Vector.add(body[i].velocity, pushUp));
}
//damage all mobs
for (let i = 0, len = mob.length; i < len; ++i) {
if (mob[i] !== this) mob[i].damage(Infinity, true);
for (let j = 0; j < 8; j++) { //in case some mobs leave things after they die
for (let i = 0, len = mob.length; i < len; ++i) {
if (mob[i] !== this) mob[i].damage(Infinity, true);
}
}
//draw stuff
@@ -1016,23 +1017,23 @@ const spawn = {
this.checkStatus();
};
},
chaser(x, y, radius = 35 + Math.ceil(Math.random() * 40)) {
mobs.spawn(x, y, 8, radius, "rgb(255,150,100)"); //"#2c9790"
let me = mob[mob.length - 1];
// Matter.Body.setDensity(me, 0.0007); //extra dense //normal is 0.001 //makes effective life much lower
me.friction = 0.1;
me.frictionAir = 0;
me.accelMag = 0.001 * Math.sqrt(simulation.accelScale);
me.g = me.accelMag * 0.6; //required if using 'gravity'
me.memory = 50;
spawn.shield(me, x, y);
me.do = function() {
this.gravity();
this.seePlayerCheck();
this.checkStatus();
this.attraction();
};
},
// chaser(x, y, radius = 35 + Math.ceil(Math.random() * 40)) {
// mobs.spawn(x, y, 8, radius, "rgb(255,150,100)"); //"#2c9790"
// let me = mob[mob.length - 1];
// // Matter.Body.setDensity(me, 0.0007); //extra dense //normal is 0.001 //makes effective life much lower
// me.friction = 0.1;
// me.frictionAir = 0;
// me.accelMag = 0.001 * Math.sqrt(simulation.accelScale);
// me.g = me.accelMag * 0.6; //required if using 'gravity'
// me.memory = 180;
// spawn.shield(me, x, y);
// me.do = function() {
// this.gravity();
// this.seePlayerByHistory(15);
// this.checkStatus();
// this.attraction();
// };
// },
grower(x, y, radius = 15) {
mobs.spawn(x, y, 7, radius, "hsl(144, 15%, 50%)");
let me = mob[mob.length - 1];
@@ -1653,7 +1654,7 @@ const spawn = {
this.checkStatus();
this.attraction();
this.repulsion();
this.laserBeam();
this.harmZone();
};
},
historyBoss(x, y, radius = 30) {
@@ -1968,6 +1969,63 @@ const spawn = {
}
};
},
blinkBoss(x, y) {
mobs.spawn(x, y, 5, 50, "rgb(215,80,190)"); //"rgb(221,102,119)"
let me = mob[mob.length - 1];
Matter.Body.rotate(me, Math.PI * 0.1);
Matter.Body.setDensity(me, 0.01); //extra dense //normal is 0.001 //makes effective life much larger
me.isBoss = true;
me.damageReduction = 0.25;
me.frictionStatic = 0;
me.friction = 0;
me.memory = 240
me.seePlayerFreq = 60
me.delay = 20 + 20 * simulation.CDScale;
me.nextBlinkCycle = me.delay;
me.blinkRange = 235
me.grenadeDelay = 30 + 50 * simulation.CDScale
me.pulseRadius = 2 * Math.min(550, 250 + simulation.difficulty * 3)
spawn.shield(me, x, y, 1);
me.onDamage = function() {
// this.cd = simulation.cycle + this.delay;
};
me.onDeath = function() {
const offAngle = Math.PI * Math.random()
for (let i = 0, len = 3; i < len; i++) {
spawn.grenade(this.position.x, this.position.y, this.grenadeDelay);
const who = mob[mob.length - 1]
const speed = 5 * simulation.accelScale;
const angle = 2 * Math.PI * i / len + offAngle
Matter.Body.setVelocity(who, {
x: speed * Math.cos(angle),
y: speed * Math.sin(angle)
});
}
}
me.do = function() {
this.seePlayerByHistory()
if (this.nextBlinkCycle < simulation.cycle && this.seePlayer.yes) { //teleport towards the player
this.nextBlinkCycle = simulation.cycle + this.delay;
const dist = Vector.sub(this.seePlayer.position, this.position);
const distMag = Vector.magnitude(dist);
ctx.beginPath();
ctx.moveTo(this.position.x, this.position.y);
if (distMag < this.blinkRange) { //if player is inside teleport range
Matter.Body.setPosition(this, this.seePlayer.position);
} else {
Matter.Body.translate(this, Vector.mult(Vector.normalise(dist), this.blinkRange));
}
spawn.grenade(this.position.x, this.position.y, this.grenadeDelay, this.pulseRadius); //spawn at new location
ctx.lineTo(this.position.x, this.position.y);
ctx.lineWidth = this.radius * 2.1;
ctx.strokeStyle = this.fill; //"rgba(0,0,0,0.5)"; //'#000'
ctx.stroke();
Matter.Body.setVelocity(this, { x: 0, y: 0 });
this.torque += (0.00004 + 0.00003 * Math.random()) * this.inertia * (Math.round(Math.random()) * 2 - 1) //randomly spin around after firing
}
this.checkStatus();
};
},
pulsarBoss(x, y, radius = 90) {
mobs.spawn(x, y, 3, radius, "#a0f");
let me = mob[mob.length - 1];
@@ -2461,6 +2519,7 @@ const spawn = {
}
};
},
striker(x, y, radius = 14 + Math.ceil(Math.random() * 25)) {
mobs.spawn(x, y, 5, radius, "rgb(221,102,119)");
let me = mob[mob.length - 1];
@@ -2480,8 +2539,8 @@ const spawn = {
if (!(simulation.cycle % this.seePlayerFreq)) { // this.seePlayerCheck(); from mobs
if (
this.distanceToPlayer2() < this.seeAtDistance2 &&
Matter.Query.ray(map, this.position, this.mPosRange()).length === 0 &&
// Matter.Query.ray(body, this.position, this.mPosRange()).length === 0 &&
Matter.Query.ray(map, this.position, this.playerPosRandomY()).length === 0 &&
// Matter.Query.ray(body, this.position, this.playerPosRandomY()).length === 0 &&
!m.isCloak
) {
this.foundPlayer();
@@ -2493,35 +2552,33 @@ const spawn = {
}
this.checkStatus();
this.attraction();
if (this.cd < simulation.cycle) {
if (this.seePlayer.recall) {
const dist = Vector.sub(this.seePlayer.position, this.position);
const distMag = Vector.magnitude(dist);
this.cd = simulation.cycle + this.delay;
ctx.beginPath();
ctx.moveTo(this.position.x, this.position.y);
if (distMag < 400) {
Matter.Body.translate(this, Vector.mult(Vector.normalise(dist), distMag - 20 - radius));
} else {
Matter.Body.translate(this, Vector.mult(Vector.normalise(dist), 300));
}
ctx.lineTo(this.position.x, this.position.y);
ctx.lineWidth = radius * 2.1;
ctx.strokeStyle = this.fill; //"rgba(0,0,0,0.5)"; //'#000'
ctx.stroke();
Matter.Body.setVelocity(this, {
x: this.velocity.x * 0.5,
y: this.velocity.y * 0.5
});
if (this.cd < simulation.cycle && this.seePlayer.recall) {
const dist = Vector.sub(this.seePlayer.position, this.position);
const distMag = Vector.magnitude(dist);
this.cd = simulation.cycle + this.delay;
ctx.beginPath();
ctx.moveTo(this.position.x, this.position.y);
if (distMag < 400) {
Matter.Body.translate(this, Vector.mult(Vector.normalise(dist), distMag - 20 - radius));
} else {
Matter.Body.translate(this, Vector.mult(Vector.normalise(dist), 300));
}
ctx.lineTo(this.position.x, this.position.y);
ctx.lineWidth = radius * 2.1;
ctx.strokeStyle = this.fill; //"rgba(0,0,0,0.5)"; //'#000'
ctx.stroke();
Matter.Body.setVelocity(this, {
x: this.velocity.x * 0.5,
y: this.velocity.y * 0.5
});
}
};
},
sneaker(x, y, radius = 15 + Math.ceil(Math.random() * 25)) {
sneaker(x, y, radius = 15 + Math.ceil(Math.random() * 10)) {
mobs.spawn(x, y, 5, radius, "transparent");
let me = mob[mob.length - 1];
Matter.Body.setDensity(me, 0.001); //extra dense //normal is 0.001 //makes effective life much larger
me.accelMag = 0.0012 * Math.sqrt(simulation.accelScale);
Matter.Body.setDensity(me, 0.002); //extra dense //normal is 0.001 //makes effective life much larger
me.accelMag = 0.001 * Math.sqrt(simulation.accelScale);
me.frictionAir = 0.01;
me.g = 0.0002; //required if using 'gravity'
me.stroke = "transparent"; //used for drawSneaker
@@ -2530,16 +2587,16 @@ const spawn = {
me.canTouchPlayer = false; //used in drawSneaker
me.collisionFilter.mask = cat.map | cat.body | cat.bullet | cat.mob //can't touch player
me.showHealthBar = false;
// me.memory = 420;
me.memory = 240;
me.do = function() {
this.gravity();
this.seePlayerCheck();
this.seePlayerByHistory(15);
this.checkStatus();
this.attraction();
//draw
if (!m.isBodiesAsleep) {
if (this.seePlayer.yes) {
if (this.alpha < 1) this.alpha += 0.01 / simulation.CDScale;
if (this.seePlayer.recall) {
if (this.alpha < 1) this.alpha += 0.003 + 0.003 / simulation.CDScale;
} else {
if (this.alpha > 0) this.alpha -= 0.03;
}
@@ -2562,7 +2619,7 @@ const spawn = {
ctx.lineTo(vertices[0].x, vertices[0].y);
ctx.fillStyle = `rgba(0,0,0,${this.alpha * this.alpha})`;
ctx.fill();
} else if (this.canTouchPlayer) {
} else if (this.canTouchPlayer) { //stealth
this.canTouchPlayer = false;
this.collisionFilter.mask = cat.map | cat.body | cat.bullet | cat.mob //can't touch player
}
@@ -3111,15 +3168,13 @@ const spawn = {
Matter.Body.setDensity(me, 0.004 + 0.0002 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
me.onDeath = function() { //helps collisions functions work better after vertex have been changed
for (let i = 0; i < 6; i++) {
spawn.grenade(this.position.x, this.position.y, 2, 4, 75 * simulation.CDScale);
spawn.grenade(this.position.x, this.position.y, 75 * simulation.CDScale);
const who = mob[mob.length - 1]
// who.collisionFilter.category = 0
who.collisionFilter.mask = cat.player | cat.map;
const speed = 4 * simulation.accelScale;
const angle = 2 * Math.PI * i / 6
Matter.Body.setVelocity(who, {
x: this.velocity.x + speed * Math.cos(angle),
y: this.velocity.y + speed * Math.sin(angle)
x: speed * Math.cos(angle),
y: speed * Math.sin(angle)
});
}
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
@@ -3128,10 +3183,8 @@ const spawn = {
me.onDamage = function() {
if (this.grenadeLimiter < 240) {
this.grenadeLimiter += 60
spawn.grenade(this.position.x, this.position.y, 2, 4, 80 + Math.floor(60 * Math.random()));
spawn.grenade(this.position.x, this.position.y, 80 + Math.floor(60 * Math.random()));
const who = mob[mob.length - 1]
// who.collisionFilter.category = 0
who.collisionFilter.mask = cat.player | cat.map;
const velocity = Vector.mult(Vector.normalise(Vector.sub(player.position, who.position)), 3 * Math.sqrt(simulation.accelScale) + 4 * Math.random())
Matter.Body.setVelocity(who, {
x: this.velocity.x + velocity.x,
@@ -3167,7 +3220,7 @@ const spawn = {
y: 0
};
me.onDeath = function() { //helps collisions functions work better after vertex have been changed
spawn.grenade(this.position.x, this.position.y, 2, 4, 75 * simulation.CDScale);
spawn.grenade(this.position.x, this.position.y, 75 * simulation.CDScale);
// mob[mob.length - 1].collisionFilter.category = 0
mob[mob.length - 1].collisionFilter.mask = cat.player | cat.map;
}
@@ -3224,8 +3277,8 @@ const spawn = {
}
};
},
grenade(x, y, radius = 2, sides = 4, lifeSpan = 90 + Math.ceil(60 / simulation.accelScale)) {
mobs.spawn(x, y, sides, radius, "rgb(215,0,190)"); //rgb(215,80,190)
grenade(x, y, lifeSpan = 90 + Math.ceil(60 / simulation.accelScale), pulseRadius = Math.min(550, 250 + simulation.difficulty * 3)) {
mobs.spawn(x, y, 4, 2, "rgb(215,0,190)"); //rgb(215,80,190)
let me = mob[mob.length - 1];
me.stroke = "transparent";
me.onHit = function() {
@@ -3241,28 +3294,28 @@ const spawn = {
me.leaveBody = false;
me.isDropPowerUp = false;
me.isBadTarget = true;
me.pulseRadius = Math.min(550, 250 + simulation.difficulty * 3)
me.onDeath = function() {
//damage player if in range
if (Vector.magnitude(Vector.sub(player.position, this.position)) < this.pulseRadius && m.immuneCycle < m.cycle) {
if (Vector.magnitude(Vector.sub(player.position, this.position)) < pulseRadius && m.immuneCycle < m.cycle) {
m.immuneCycle = m.cycle + tech.collisionImmuneCycles; //player is immune to damage
m.damage(0.02 * simulation.dmgScale);
}
simulation.drawList.push({ //add dmg to draw queue
x: this.position.x,
y: this.position.y,
radius: this.pulseRadius,
radius: pulseRadius,
color: "rgba(255,0,220,0.3)",
time: simulation.drawTime
});
};
me.showHealthBar = false;
me.collisionFilter.category = cat.mobBullet;
me.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet;
// me.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet;
me.collisionFilter.mask = 0
me.do = function() {
this.timeLimit();
ctx.beginPath(); //draw explosion outline
ctx.arc(this.position.x, this.position.y, this.pulseRadius * (1.01 - this.timeLeft / this.lifeSpan), 0, 2 * Math.PI); //* this.fireCycle / this.fireDelay
ctx.arc(this.position.x, this.position.y, pulseRadius * (1.01 - this.timeLeft / this.lifeSpan), 0, 2 * Math.PI); //* this.fireCycle / this.fireDelay
ctx.fillStyle = "rgba(255,0,220,0.05)";
ctx.fill();
};
@@ -3507,8 +3560,8 @@ const spawn = {
// if (!(simulation.cycle % this.seePlayerFreq)) {
// if (
// this.distanceToPlayer2() < this.seeAtDistance2 &&
// Matter.Query.ray(map, this.position, this.mPosRange()).length === 0 &&
// Matter.Query.ray(body, this.position, this.mPosRange()).length === 0 &&
// Matter.Query.ray(map, this.position, this.playerPosRandomY()).length === 0 &&
// Matter.Query.ray(body, this.position, this.playerPosRandomY()).length === 0 &&
// !m.isCloak
// ) {
// this.foundPlayer();
@@ -3552,7 +3605,7 @@ const spawn = {
this.attraction();
};
},
snakeBoss(x, y, radius = 75) { //snake boss with a laser head
snakeBoss(x, y, radius = 60) { //snake boss with a laser head
const color1 = "#f27"
mobs.spawn(x, y, 8, radius, color1); //"rgb(55,170,170)"
let me = mob[mob.length - 1];
@@ -3561,7 +3614,7 @@ const spawn = {
me.accelMag = 0.00075 * simulation.accelScale;
me.memory = 250;
me.laserRange = 500;
Matter.Body.setDensity(me, 0.001 + 0.0001 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
Matter.Body.setDensity(me, 0.0016 + 0.0001 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
me.onDeath = function() {
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
for (let i = 0; i < mob.length; i++) { //wake up tail mobs
@@ -3573,10 +3626,11 @@ const spawn = {
}
};
me.do = function() {
this.seePlayerCheck();
// this.seePlayerCheck();
this.seePlayerByHistory()
this.checkStatus();
this.attraction();
this.laserBeam();
this.harmZone();
};
//snake tail

View File

@@ -1018,6 +1018,7 @@
maxCount: 3,
count: 0,
frequency: 1,
frequencyDefault: 1,
isBotTech: true,
allowed() {
return !tech.sporesOnDeath && !tech.nailsDeathMob && !tech.isExplodeMob && !tech.isMobBlockFling && !tech.iceIXOnDeath
@@ -1036,6 +1037,7 @@
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
isBotTech: true,
allowed() {
return tech.botSpawner
@@ -1054,6 +1056,7 @@
maxCount: 9,
count: 0,
frequency: 1,
frequencyDefault: 1,
isBot: true,
isBotTech: true,
allowed() {
@@ -1078,6 +1081,7 @@
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
isBotTech: true,
allowed() {
return tech.nailBotCount > 1 && !b.hasBotUpgrade()
@@ -1103,6 +1107,7 @@
maxCount: 9,
count: 0,
frequency: 1,
frequencyDefault: 1,
isBot: true,
isBotTech: true,
allowed() {
@@ -1127,6 +1132,7 @@
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
isBotTech: true,
allowed() {
return tech.foamBotCount > 1 && !b.hasBotUpgrade()
@@ -1152,6 +1158,7 @@
maxCount: 9,
count: 0,
frequency: 1,
frequencyDefault: 1,
isBot: true,
isBotTech: true,
allowed() {
@@ -1176,6 +1183,7 @@
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
isBotTech: true,
allowed() {
return tech.boomBotCount > 1 && !b.hasBotUpgrade()
@@ -1201,6 +1209,7 @@
maxCount: 9,
count: 0,
frequency: 1,
frequencyDefault: 1,
isBot: true,
isBotTech: true,
allowed() {
@@ -1225,6 +1234,7 @@
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
isBotTech: true,
allowed() {
return tech.laserBotCount > 1 && !b.hasBotUpgrade()
@@ -1250,7 +1260,7 @@
maxCount: 9,
count: 0,
frequency: 1,
frequencyDefault: 1,
isBot: true,
isBotTech: true,
allowed() {
@@ -1275,6 +1285,7 @@
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
isBotTech: true,
allowed() {
return tech.orbitBotCount > 1 && !b.hasBotUpgrade()
@@ -1310,6 +1321,7 @@
maxCount: 9,
count: 0,
frequency: 1,
frequencyDefault: 1,
isBot: true,
isBotTech: true,
allowed() {
@@ -1334,6 +1346,7 @@
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
isBotTech: true,
allowed() {
return tech.dynamoBotCount > 1 && !b.hasBotUpgrade()
@@ -1359,6 +1372,7 @@
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
isBotTech: true,
allowed() {
return powerUps.research.count > 2 || build.isExperimentSelection
@@ -1379,6 +1393,7 @@
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
isBotTech: true,
allowed() {
return (b.totalBots() > 1 && powerUps.research.count > 0) || build.isExperimentSelection
@@ -1407,6 +1422,7 @@
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
isBotTech: true,
allowed() {
return b.totalBots() > 3 && !tech.isEnergyHealth
@@ -1425,6 +1441,7 @@
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
isBotTech: true,
allowed() {
return b.totalBots() > 3
@@ -1443,6 +1460,7 @@
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
isBotTech: true,
// isNonRefundable: true,
isBadRandomOption: true,
@@ -3454,7 +3472,7 @@
},
{
name: "ceramic needles",
description: `your <strong>needles</strong> pierce <strong>shields</strong><br>directly <strong class='color-d'>damaging</strong> shielded mobs`,
description: `<strong>needles</strong> pierce <strong>shields</strong><br>directly <strong class='color-d'>damaging</strong> shielded mobs`,
isGunTech: true,
maxCount: 1,
count: 0,
@@ -3506,7 +3524,7 @@
},
{
name: "rivet diameter",
description: `your <strong>rivets</strong> are <strong>20%</strong> larger<br>increases mass and physical <strong class='color-d'>damage</strong>`,
description: `<strong>rivets</strong> are <strong>20%</strong> larger<br>increases mass and physical <strong class='color-d'>damage</strong>`,
isGunTech: true,
maxCount: 9,
count: 0,
@@ -3769,7 +3787,7 @@
},
{
name: "shotgun slug",
description: "the <strong>shotgun</strong> fires a huge dense <strong>bullet</strong>",
description: "<strong>shotgun</strong> lobs <strong>1</strong> huge <strong>bullet</strong>",
isGunTech: true,
maxCount: 1,
count: 0,
@@ -3788,7 +3806,7 @@
},
{
name: "nail-shot",
description: "the <strong>shotgun</strong> fires a burst of <strong>nails</strong>",
description: "<strong>shotgun</strong> fires <strong>17</strong> <strong>nails</strong>",
isGunTech: true,
maxCount: 1,
count: 0,
@@ -3807,7 +3825,7 @@
},
{
name: "worm-shot",
description: "the <strong>shotgun</strong> fires <strong>3-4</strong> <strong class='color-p' style='letter-spacing: -0.8px;'>worms</strong>", //<br><strong class='color-p' style='letter-spacing: -0.8px;'>worms</strong> seek out nearby mobs
description: "<strong>shotgun</strong> hatches <strong>3-4</strong> mob seeking <strong class='color-p' style='letter-spacing: -0.8px;'>worms</strong>", //<br><strong class='color-p' style='letter-spacing: -0.8px;'>worms</strong> seek out nearby mobs
isGunTech: true,
maxCount: 1,
count: 0,
@@ -3826,7 +3844,7 @@
},
{
name: "foam-shot",
description: "the <strong>shotgun</strong> fires <strong>13</strong> <strong>foam</strong> bubbles",
description: "<strong>shotgun</strong> sprays <strong>13</strong> sticky <strong>foam</strong> bubbles",
isGunTech: true,
maxCount: 1,
count: 0,
@@ -3845,7 +3863,7 @@
},
{
name: "ice-shot",
description: "the <strong>shotgun</strong> fires <strong>18</strong> <strong class='color-s'>ice IX</strong> crystals",
description: "<strong>shotgun</strong> grows <strong>18</strong> freezing <strong class='color-s'>ice IX</strong> crystals",
isGunTech: true,
maxCount: 1,
count: 0,
@@ -3864,7 +3882,7 @@
},
{
name: "needle-shot",
description: "the <strong>shotgun</strong> fires <strong>12</strong> mob piercing <strong>needles</strong>",
description: "<strong>shotgun</strong> propels <strong>12</strong> mob piercing <strong>needles</strong>",
isGunTech: true,
maxCount: 1,
count: 0,
@@ -3956,7 +3974,7 @@
},
{
name: "super sized",
description: `your <strong>super balls</strong> are <strong>20%</strong> larger<br>increases mass and physical <strong class='color-d'>damage</strong>`,
description: `<strong>super balls</strong> are <strong>20%</strong> larger<br>increases mass and physical <strong class='color-d'>damage</strong>`,
isGunTech: true,
maxCount: 9,
count: 0,
@@ -4569,7 +4587,7 @@
},
{
name: "irradiated drones",
description: "<strong class='color-p'>irradiate</strong> the space around your <strong>drones</strong><br>reduce <strong class='color-g'>ammo</strong>/<strong class='color-f'>efficiency</strong> by <strong>75%</strong>",
description: "the space around <strong>drones</strong> is <strong class='color-p'>irradiated</strong><br>reduce <strong class='color-g'>ammo</strong>/<strong class='color-f'>efficiency</strong> by <strong>75%</strong>",
isGunTech: true,
maxCount: 1,
count: 0,
@@ -4880,7 +4898,7 @@
},
{
name: "diffraction grating",
description: `your <strong class='color-laser'>laser</strong> gains a <strong>diverging</strong> beam`,
description: `<strong class='color-laser'>laser</strong> gains a <strong>diverging</strong> beam`,
isGunTech: true,
maxCount: 9,
count: 0,
@@ -5048,8 +5066,8 @@
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
frequency: 3,
frequencyDefault: 3,
allowed() {
return (m.fieldUpgrades[m.fieldMode].name === "standing wave harmonics" || m.fieldUpgrades[m.fieldMode].name === "pilot wave") && (build.isExperimentSelection || powerUps.research.count > 1)
},
@@ -5193,8 +5211,8 @@
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
frequency: 3,
frequencyDefault: 3,
allowed() {
return (m.fieldUpgrades[m.fieldMode].name === "perfect diamagnetism" || m.fieldUpgrades[m.fieldMode].name === "negative mass field") && (build.isExperimentSelection || powerUps.research.count > 3)
},
@@ -5508,7 +5526,8 @@
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequency: 3,
frequencyDefault: 3,
isBot: true,
isBotTech: true,
allowed() {
@@ -5613,8 +5632,8 @@
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
frequency: 3,
frequencyDefault: 3,
allowed() {
return m.fieldUpgrades[m.fieldMode].name === "time dilation" && (build.isExperimentSelection || powerUps.research.count > 2)
},
@@ -5699,8 +5718,8 @@
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
frequency: 3,
frequencyDefault: 3,
allowed() {
return (m.fieldUpgrades[m.fieldMode].name === "metamaterial cloaking" || m.fieldUpgrades[m.fieldMode].name === "pilot wave") && (build.isExperimentSelection || powerUps.research.count > 0)
},
@@ -5802,8 +5821,8 @@
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
frequency: 3,
frequencyDefault: 3,
allowed() {
return m.fieldUpgrades[m.fieldMode].name === "wormhole" && (build.isExperimentSelection || powerUps.research.count > 2) && tech.duplicationChance() < 1
},

View File

@@ -1,16 +1,12 @@
******************************************************** NEXT PATCH ********************************************************
shotgun balance
ice-shot: less spread, higher damage, more crystals
needle-shot: more needles, higher damage, less spread
foam-shot: 1 more bubble
power up selection and pause menu elements scroll individually now
it looks great on my computer, but different operating systems and browsers are unpredictable
let me know if text is hidden or if it doesn't scroll for you and what OS and browser you're on
******************************************************** TODO ********************************************************
block shattering
get code from planetesimals
https://codepen.io/lilgreenland/pen/jrMvaB?editors=0010
mob that grows or gets a shield when player is near
and charges when player is near
charge triggers an escape mode
@@ -174,10 +170,6 @@ movement fluidity
wall grab?
maybe remove falling damage and block damage?
redblobgames.com/articles/visibility
https://github.com/Silverwolf90/2d-visibility/tree/master/src
could apply to explosions, neutron bomb, player LOS
have a mob apply a positive status effect on other mobs,
heal?
make it yellow
@@ -198,6 +190,7 @@ n-gon outreach ideas
blocks on buttons teleport into the button endlessly if they are being slowly floated away
maybe add a cooldown?
can't reproduce
ants marching outline doesn't sync right on safari anymore.
@@ -340,13 +333,6 @@ mob: molecule shapes - 2 separate mobs joined by a bond
spin when attacking player?
increase constraint length when attacking
mob vision: look at player history
build a new type of attraction for mobs
if mobs can't see player, they check to see if they can see where the player was in the history
if mobs can't see player, they could check to see if they can find player in the past
https://abitawake.com/news/articles/enemy-ai-chasing-a-player-without-navigation2d-or-a-star-pathfinding
write find in spawn undo exploder, but commented out
Mob: "Tentacle": Sits on wall. Is a black blob. When you get near it, reaches out and grabs you, similar to wires. Does not deal damage.
maybe it could be immune to damage? but it is spawned by an actual mob