experiment and junk tech: decomposers - mobs leave behind spawns when they die

new levelBoss - a cluster of larger spawns
  while it's alive all mobs other leave behind spawns

added block collisions to most no collide mobs
  (this should buff block throwing and pilot wave)
This commit is contained in:
landgreen
2021-04-15 05:23:26 -07:00
parent b217a50f75
commit a5aea4ccc5
11 changed files with 484 additions and 263 deletions

View File

@@ -208,7 +208,7 @@ const b = {
fireCD: 1,
setFireCD() {
b.fireCD = tech.fireRate * tech.slowFire * tech.researchHaste * tech.aimDamage / tech.fastTime
if (tech.isFireRateForGuns) b.fireCD *= Math.pow(0.83, b.inventory.length)
if (tech.isFireRateForGuns) b.fireCD *= Math.pow(0.86, b.inventory.length)
if (tech.isFireNotMove) b.fireCD *= 0.33
},
fireAttributes(dir, rotate = true) {
@@ -1102,7 +1102,7 @@ const b = {
// const futurePos = this.lockedOn ? :Vector.add(this.position, Vector.mult(this.velocity, 50))
for (let i = 0, len = mob.length; i < len; ++i) {
if (
mob[i].alive && mob[i].dropPowerUp &&
mob[i].alive && mob[i].isDropPowerUp &&
Matter.Query.ray(map, this.position, mob[i].position).length === 0
// && Matter.Query.ray(body, this.position, mob[i].position).length === 0
) {
@@ -1605,7 +1605,7 @@ const b = {
for (let i = 0, len = mob.length; i < len; ++i) {
if (
Vector.magnitudeSquared(Vector.sub(this.position, mob[i].position)) < 2000000 &&
mob[i].dropPowerUp &&
mob[i].isDropPowerUp &&
Matter.Query.ray(map, this.position, mob[i].position).length === 0 &&
Matter.Query.ray(body, this.position, mob[i].position).length === 0
) {
@@ -1771,7 +1771,7 @@ const b = {
if (!(simulation.cycle % this.lookFrequency)) { //find mob targets
for (let i = 0, len = mob.length; i < len; ++i) {
if (Vector.magnitudeSquared(Vector.sub(this.position, mob[i].position)) < 500000 &&
mob[i].dropPowerUp &&
// mob[i].isDropPowerUp &&
Matter.Query.ray(map, this.position, mob[i].position).length === 0 &&
Matter.Query.ray(body, this.position, mob[i].position).length === 0) {
this.endCycle = 0 //end life if mob is near and visible
@@ -1847,7 +1847,7 @@ const b = {
this.lockedOn = null;
let closeDist = Infinity;
for (let i = 0, len = mob.length; i < len; ++i) {
if (mob[i].dropPowerUp && Matter.Query.ray(map, this.position, mob[i].position).length === 0) {
if (Matter.Query.ray(map, this.position, mob[i].position).length === 0) {
const targetVector = Vector.sub(this.position, mob[i].position)
const dist = Vector.magnitude(targetVector) * (Math.random() + 0.5);
if (dist < closeDist) {
@@ -1877,7 +1877,7 @@ const b = {
// this.lockedOn = null;
// let closeDist = Infinity;
// for (let i = 0, len = mob.length; i < len; ++i) {
// if (mob[i].dropPowerUp && Matter.Query.ray(map, this.position, mob[i].position).length === 0) {
// if (mob[i].isDropPowerUp && Matter.Query.ray(map, this.position, mob[i].position).length === 0) {
// // Matter.Query.ray(body, this.position, mob[i].position).length === 0
// const targetVector = Vector.sub(this.position, mob[i].position)
// const dist = Vector.magnitude(targetVector);
@@ -1948,7 +1948,7 @@ const b = {
mobs.statusSlow(who, 180)
this.endCycle = simulation.cycle
// if (tech.isHeavyWater) mobs.statusDoT(who, 0.15, 300)
if (tech.iceEnergy && !who.shield && !who.isShielded && who.dropPowerUp && who.alive) {
if (tech.iceEnergy && !who.shield && !who.isShielded && who.isDropPowerUp && who.alive) {
setTimeout(function() {
if (!who.alive) {
m.energy += tech.iceEnergy * 0.8
@@ -1968,7 +1968,7 @@ const b = {
let closeDist = Infinity;
for (let i = 0, len = mob.length; i < len; ++i) {
if (
mob[i].dropPowerUp &&
mob[i].isDropPowerUp &&
Matter.Query.ray(map, this.position, mob[i].position).length === 0 &&
Matter.Query.ray(body, this.position, mob[i].position).length === 0
) {
@@ -2070,7 +2070,7 @@ const b = {
let closeDist = Infinity;
for (let i = 0, len = mob.length; i < len; ++i) {
if (
mob[i].dropPowerUp &&
mob[i].isDropPowerUp &&
Matter.Query.ray(map, this.position, mob[i].position).length === 0 &&
Matter.Query.ray(body, this.position, mob[i].position).length === 0
) {
@@ -2283,7 +2283,7 @@ const b = {
if (tech.isFoamAttract) {
for (let i = 0, len = mob.length; i < len; i++) {
if (mob[i].dropPowerUp && Vector.magnitude(Vector.sub(mob[i].position, this.position)) < 375 && mob[i].alive && Matter.Query.ray(map, this.position, mob[i].position).length === 0) {
if (mob[i].isDropPowerUp && Vector.magnitude(Vector.sub(mob[i].position, this.position)) < 375 && mob[i].alive && Matter.Query.ray(map, this.position, mob[i].position).length === 0) {
this.force = Vector.mult(Vector.normalise(Vector.sub(mob[i].position, this.position)), this.mass * 0.004)
const slow = 0.9
Matter.Body.setVelocity(this, {
@@ -2304,14 +2304,14 @@ const b = {
targetedNail(position, num = 1, speed = 40 + 10 * Math.random(), range = 1200, isRandomAim = true) {
const targets = [] //target nearby mobs
for (let i = 0, len = mob.length; i < len; i++) {
if (mob[i].dropPowerUp) {
const dist = Vector.magnitude(Vector.sub(position, mob[i].position));
if (dist < range &&
Matter.Query.ray(map, position, mob[i].position).length === 0 &&
Matter.Query.ray(body, position, mob[i].position).length === 0) {
targets.push(Vector.add(mob[i].position, Vector.mult(mob[i].velocity, dist / 60))) //predict where the mob will be in a few cycles
}
// if (mob[i].isDropPowerUp) {
const dist = Vector.magnitude(Vector.sub(position, mob[i].position));
if (dist < range &&
Matter.Query.ray(map, position, mob[i].position).length === 0 &&
Matter.Query.ray(body, position, mob[i].position).length === 0) {
targets.push(Vector.add(mob[i].position, Vector.mult(mob[i].velocity, dist / 60))) //predict where the mob will be in a few cycles
}
// }
}
for (let i = 0; i < num; i++) {
if (targets.length > 0) { // aim near a random target in array
@@ -2859,7 +2859,7 @@ const b = {
let closeDist = this.range;
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 && mob[i].isDropPowerUp &&
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

@@ -138,7 +138,7 @@ function collisionChecks(event) {
y: mob[k].velocity.y - 8 * Math.sin(angle)
});
if (tech.isAnnihilation && !mob[k].shield && !mob[k].isShielded && !mob[k].isBoss && mob[k].dropPowerUp && m.energy > 0.34 * m.maxEnergy) {
if (tech.isAnnihilation && !mob[k].shield && !mob[k].isShielded && !mob[k].isBoss && mob[k].isDropPowerUp && m.energy > 0.34 * m.maxEnergy) {
m.energy -= 0.33 * m.maxEnergy
m.immuneCycle = 0; //player doesn't go immune to collision damage
mob[k].death();
@@ -184,7 +184,7 @@ function collisionChecks(event) {
let dmg = 0.05 * b.dmgScale * v * obj.mass * tech.throwChargeRate;
if (mob[k].isShielded) dmg *= 0.35
mob[k].damage(dmg, true);
if (tech.isBlockPowerUps && !mob[k].alive && mob[k].dropPowerUp) {
if (tech.isBlockPowerUps && !mob[k].alive && mob[k].isDropPowerUp) {
let type = tech.isEnergyNoAmmo ? "heal" : "ammo"
if (Math.random() < 0.4) {
type = "heal"

View File

@@ -331,7 +331,8 @@ const build = {
// text += `<div class="pause-grid-module"><div class="grid-title"><div class="circle-grid junk"></div> &nbsp; ${tech.tech[i].name} ${isCount}</div>${tech.tech[i].description}</div></div>`
techID.innerHTML = `<div class="grid-title"><div class="circle-grid junk"></div> &nbsp; ${tech.tech[i].name} ${isCount}</div>${tech.tech[i].description}</div>`
} else if (tech.tech[i].isExperimentalMode) {
techID.innerHTML = `${tech.tech[i].description}</div>`
// techID.innerHTML = `${tech.tech[i].description}</div>`
text += `<div id="tech-${i}" class="experiment-grid-module" onclick="build.choosePowerUp(this,${i},'tech')"><div class="grid-title">${tech.tech[i].name}</div> ${tech.tech[i].description}</div>`
} else {
techID.innerHTML = `<div class="grid-title"><div class="circle-grid tech"></div> &nbsp; ${tech.tech[i].name} ${isCount}</div>${tech.tech[i].description}</div>`
}

View File

@@ -12,7 +12,7 @@ const level = {
start() {
if (level.levelsCleared === 0) { //this code only runs on the first level
// simulation.enableConstructMode() //used to build maps in testing mode
// level.difficultyIncrease(50)
// level.difficultyIncrease(11)
// simulation.zoomScale = 1000;
// simulation.setZoom();
// m.setField("nano-scale manufacturing")
@@ -772,6 +772,33 @@ const level = {
mapB.portalPair = mapA
return [portalA, portalB, mapA, mapB]
},
drip(x, yMin, yMax, period = 100, color = "hsla(160, 100%, 35%, 0.5)") {
return {
x: x,
y: yMin,
period: period,
dropCycle: 0,
speed: 0,
draw() {
if (!m.isBodiesAsleep) {
if (this.dropCycle < simulation.cycle) { //reset
this.dropCycle = simulation.cycle + this.period + Math.floor(40 * Math.random())
this.y = yMin
this.speed = 1
} else { //fall
this.speed += 0.35 //acceleration from gravity
this.y += this.speed
}
}
if (this.y < yMax) { //draw
ctx.fillStyle = color //"hsla(160, 100%, 35%,0.75)"
ctx.beginPath();
ctx.arc(this.x, this.y, 8, 0, 2 * Math.PI);
ctx.fill();
}
}
}
},
hazard(x, y, width, height, damage = 0.003, color = "hsla(160, 100%, 35%,0.75)") {
return {
min: {
@@ -1086,18 +1113,18 @@ const level = {
// spawn.ghoster(2900, -500)
// spawn.launcherBoss(1200, -500)
// spawn.laserTargetingBoss(1600, -400)
// spawn.striker(1600, -500)
// spawn.striker(4600, -500)
// spawn.laserTargetingBoss(1700, -120)
// spawn.bomberBoss(1400, -500)
// spawn.sniper(1800, -120)
// spawn.streamBoss(1600, -500)
// spawn.orbitalBoss(1600, -500)
// spawn.cellBossCulture(1600, -500)
spawn.spawnerBossCulture(1600, -500)
// spawn.shieldingBoss(1600, -500)
// spawn.beamer(1200, -500)
// spawn.shield(mob[mob.length - 1], 1800, -120, 1);
spawn.nodeGroup(1200, -500, "pulsar")
// spawn.nodeGroup(1200, -500, "pulsar")
// spawn.snakeBoss(1200, -500)
// spawn.powerUpBoss(2900, -500)
// spawn.randomMob(1600, -500)
@@ -1714,29 +1741,13 @@ const level = {
const balance3 = level.spinner(2608, 1900, 584, 25, 0.001) //falling
const balance4 = level.spinner(9300, 2205, 25, 380, 0.001) //exit
const drip = {
x: 7150,
y: 0,
speed: 0
}
const drip1 = level.drip(6100, 1900, 2900, 100)
const drip2 = level.drip(7300, 1900, 2900, 150)
const drip3 = level.drip(8750, 1900, 2900, 70)
level.custom = () => {
const dripCycle = (simulation.cycle % 200) //drips
if (dripCycle < 70) {
if (!m.isBodiesAsleep) {
if (dripCycle === 0) {
drip.y = 1900
drip.x = 4600 + 4400 * Math.random()
drip.speed = 1
}
drip.speed += 0.35 //acceleration from gravity
drip.y += drip.speed
}
// if (drip.y > 2900) console.log(dripCycle)
ctx.fillStyle = "hsla(160, 100%, 35%, 0.5)" //"hsla(160, 100%, 35%,0.75)"
ctx.beginPath();
ctx.arc(drip.x, drip.y, 8, 0, 2 * Math.PI);
ctx.fill();
}
drip1.draw();
drip2.draw();
drip3.draw();
button.query();
button.draw();

View File

@@ -307,6 +307,12 @@ const mobs = {
this.seePlayer.position.y = player.position.y;
}
},
// alwaysSeePlayerIfRemember() {
// if (!m.isCloak && this.seePlayer.recall) {
// this.seePlayer.position.x = player.position.x;
// this.seePlayer.position.y = player.position.y;
// }
// },
seePlayerCheck() {
if (!(simulation.cycle % this.seePlayerFreq)) {
if (
@@ -980,7 +986,7 @@ const mobs = {
explode(mass = this.mass) {
if (m.immuneCycle < m.cycle) {
m.damage(Math.min(Math.max(0.02 * Math.sqrt(mass), 0.01), 0.35) * simulation.dmgScale);
this.dropPowerUp = false;
this.isDropPowerUp = false;
this.death(); //death with no power up or body
}
},
@@ -988,7 +994,7 @@ const mobs = {
if (!m.isBodiesAsleep) {
this.timeLeft--;
if (this.timeLeft < 0) {
this.dropPowerUp = false;
this.isDropPowerUp = false;
this.death(); //death with no power up
}
}
@@ -1014,9 +1020,9 @@ const mobs = {
if (this.isBoss) dmg *= 0.25
//energy and heal drain should be calculated after damage boosts
if (tech.energySiphon && dmg !== Infinity && this.dropPowerUp) m.energy += Math.min(this.health, dmg) * tech.energySiphon
if (tech.energySiphon && dmg !== Infinity && this.isDropPowerUp) m.energy += Math.min(this.health, dmg) * tech.energySiphon
if (tech.healthDrain && dmg !== Infinity && this.dropPowerUp) {
if (tech.healthDrain && dmg !== Infinity && this.isDropPowerUp) {
m.addHealth(Math.min(this.health, dmg) * tech.healthDrain)
if (m.health > m.maxHealth) m.health = m.maxHealth
}
@@ -1036,12 +1042,24 @@ const mobs = {
// to use declare custom method in mob spawn
},
leaveBody: true,
dropPowerUp: true,
isDropPowerUp: true,
death() {
this.onDeath(this); //custom death effects
this.removeConsBB();
this.alive = false; //triggers mob removal in mob[i].replace(i)
if (this.dropPowerUp) {
if (this.isDropPowerUp) {
if (tech.deathSpawnsFromBoss || (tech.deathSpawns && this.isDropPowerUp)) {
const spawns = tech.deathSpawns + tech.deathSpawnsFromBoss
const len = Math.min(12, spawns * Math.ceil(Math.random() * simulation.difficulty * spawns))
for (let i = 0; i < len; i++) {
spawn.spawns(this.position.x + (Math.random() - 0.5) * radius * 2.5, this.position.y + (Math.random() - 0.5) * radius * 2.5);
Matter.Body.setVelocity(mob[mob.length - 1], {
x: this.velocity.x + (Math.random() - 0.5) * 10,
y: this.velocity.x + (Math.random() - 0.5) * 10
});
}
}
if (tech.isEnergyLoss) m.energy *= 0.75;
powerUps.spawnRandomPowerUp(this.position.x, this.position.y);
m.lastKillCycle = m.cycle; //tracks the last time a kill was made, mostly used in simulation.checks()
@@ -1055,7 +1073,10 @@ const mobs = {
}
if (tech.isBotSpawnerReset) {
for (let i = 0, len = bullet.length; i < len; i++) {
if (bullet[i].botType && !bullet[i].isKeep) bullet[i].endCycle = simulation.cycle + 660 //10 seconds and 1 extra second for fun
if (bullet[i].botType && bullet[i].endCycle !== Infinity) {
console.log(bullet[i].endCycle)
bullet[i].endCycle = simulation.cycle + 660 //10 seconds and 1 extra second for fun
}
}
}
if (Math.random() < tech.botSpawner) {

View File

@@ -348,6 +348,7 @@ const m = {
// tech.removeLoreTechFromPool();
// tech.addLoreTechToPool();
// tech.removeJunkTechFromPool();
tech.cancelCount = 0;
tech.armorFromPowerUps = 0;
tech.totalCount = 0;
const randomBotCount = b.totalBots()
@@ -1317,7 +1318,7 @@ const m = {
x: player.velocity.x - (20 * unit.x) / massRoot,
y: player.velocity.y - (20 * unit.y) / massRoot
});
if (who.dropPowerUp && player.speed < 12) {
if (who.isDropPowerUp && player.speed < 12) {
const massRootCap = Math.sqrt(Math.min(10, Math.max(0.4, who.mass))); // masses above 12 can start to overcome the push back
Matter.Body.setVelocity(player, {
x: 0.9 * player.velocity.x + 0.6 * unit.x * massRootCap,
@@ -1880,6 +1881,14 @@ const m = {
simulation.isTimeSkipping = true;
m.cycle++;
simulation.gravity();
if (tech.isFireMoveLock && input.fire) {
// Matter.Body.setVelocity(player, {
// x: 0,
// y: -55 * player.mass * simulation.g //undo gravity before it is added
// });
player.force.x = 0
player.force.y = 0
}
Engine.update(engine, simulation.delta);
// level.checkZones();
// level.checkQuery();
@@ -2125,7 +2134,7 @@ const m = {
// //draw outline of shield
// ctx.fillStyle = `rgba(140,217,255,0.5)`
// ctx.fill()
// } else if (tech.superposition && inPlayer[i].dropPowerUp) {
// } else if (tech.superposition && inPlayer[i].isDropPowerUp) {
// // inPlayer[i].damage(0.4 * b.dmgScale); //damage mobs inside the player
// // m.energy += 0.005;
@@ -2919,7 +2928,7 @@ const m = {
y: mob[k].velocity.y - 8 * Math.sin(angle)
});
if (tech.isAnnihilation && !mob[k].shield && !mob[k].isShielded && !mob[k].isBoss && mob[k].dropPowerUp && m.energy > 0.34 * m.maxEnergy) {
if (tech.isAnnihilation && !mob[k].shield && !mob[k].isShielded && !mob[k].isBoss && mob[k].isDropPowerUp && m.energy > 0.34 * m.maxEnergy) {
m.energy -= 0.33 * m.maxEnergy
m.immuneCycle = 0; //player doesn't go immune to collision damage
mob[k].death();
@@ -2965,7 +2974,7 @@ const m = {
let dmg = 0.05 * b.dmgScale * v * obj.mass * tech.throwChargeRate;
if (mob[k].isShielded) dmg *= 0.35
mob[k].damage(dmg, true);
if (tech.isBlockPowerUps && !mob[k].alive && mob[k].dropPowerUp) {
if (tech.isBlockPowerUps && !mob[k].alive && mob[k].isDropPowerUp) {
let type = tech.isEnergyNoAmmo ? "heal" : "ammo"
if (Math.random() < 0.4) {
type = "heal"

View File

@@ -710,6 +710,7 @@ const simulation = {
let holdTarget; //if player is holding something this remembers it before it gets deleted
if (m.holdingTarget) holdTarget = m.holdingTarget;
tech.deathSpawnsFromBoss = 0;
simulation.fallHeight = 3000;
m.fireCDcycle = 0
m.drop();

View File

@@ -83,7 +83,7 @@ const spawn = {
}
}
},
randomLevelBoss(x, y, options = ["shieldingBoss", "orbitalBoss", "historyBoss", "shooterBoss", "cellBossCulture", "bomberBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss", "powerUpBoss", "snakeBoss", "streamBoss", "pulsarBoss"]) {
randomLevelBoss(x, y, options = ["shieldingBoss", "orbitalBoss", "historyBoss", "shooterBoss", "cellBossCulture", "bomberBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss", "powerUpBoss", "snakeBoss", "streamBoss", "pulsarBoss", "spawnerBossCulture"]) {
// 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)
},
@@ -472,7 +472,7 @@ const spawn = {
//tether to other blocks
ctx.beginPath();
for (let i = 0, len = mob.length; i < len; i++) {
if (mob[i].isGrouper && mob[i] != this && mob[i].dropPowerUp) { //don't tether to self, bullets, shields, ...
if (mob[i].isGrouper && mob[i] != this && mob[i].isDropPowerUp) { //don't tether to self, bullets, shields, ...
const distance2 = Vector.magnitudeSquared(Vector.sub(this.position, mob[i].position))
if (distance2 < this.groupingRangeMax) {
if (!mob[i].seePlayer.recall) mob[i].seePlayerCheck(); //wake up sleepy mobs
@@ -529,7 +529,7 @@ const spawn = {
me.seePlayerFreq = Math.floor(11 + 7 * Math.random())
me.seeAtDistance2 = 1400000;
me.cellMassMax = 70
me.collisionFilter.mask = cat.player | cat.bullet //| cat.map | cat.body
me.collisionFilter.mask = cat.player | cat.bullet | cat.body //| cat.map | cat.body
Matter.Body.setDensity(me, 0.00035) // normal density is 0.001 // this reduces life by half and decreases knockback
const k = 642 //k=r^2/m
me.split = function() {
@@ -584,10 +584,103 @@ const spawn = {
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
} else {
this.leaveBody = false;
this.dropPowerUp = false;
this.isDropPowerUp = false;
}
}
},
spawnerBossCulture(x, y, radius = 50, num = 8 + Math.min(20, simulation.difficulty * 0.4)) {
tech.deathSpawnsFromBoss += 0.4
const spawnID = Math.random()
for (let i = 0; i < num; i++) spawn.spawnerBoss(x, y, radius, spawnID)
},
spawnerBoss(x, y, radius, spawnID) {
mobs.spawn(x + Math.random(), y + Math.random(), 4, radius, "rgba(255,60,0,0.3)") //);
let me = mob[mob.length - 1];
me.isBoss = true;
me.isSpawnBoss = true;
me.spawnID = spawnID
me.accelMag = 0.0002 * simulation.accelScale;
me.memory = Infinity;
me.showHealthBar = false;
me.isVerticesChange = true
me.frictionAir = 0.012
me.seePlayerFreq = Math.floor(11 + 7 * Math.random())
me.seeAtDistance2 = 200000 //1400000;
me.cellMassMax = 70
me.stroke = "transparent"
me.collisionFilter.mask = cat.player | cat.bullet | cat.body //| cat.map //"rgba(255,60,0,0.3)"
// Matter.Body.setDensity(me, 0.0014) // normal density is 0.001
Matter.Body.setAngularVelocity(me, 0.12 * (Math.random() - 0.5))
// spawn.shield(me, x, y, 1);
me.onHit = function() { //run this function on hitting player
this.explode();
};
me.doAwake = function() {
if (!m.isBodiesAsleep) {
this.alwaysSeePlayer();
this.checkStatus();
this.attraction();
// if (this.seePlayer.recall && this.mass < this.cellMassMax) { //grow cell radius
// const scale = 1 + 0.0002 * this.cellMassMax / this.mass;
// Matter.Body.scale(this, scale, scale);
// this.radius = Math.sqrt(this.mass * k / Math.PI)
// }
if (!(simulation.cycle % this.seePlayerFreq)) { //move away from other mobs
const repelRange = 40
const attractRange = 240
for (let i = 0, len = mob.length; i < len; i++) {
if (mob[i].isSpawnBoss && mob[i].id !== this.id) {
const sub = Vector.sub(this.position, mob[i].position)
const dist = Vector.magnitude(sub)
if (dist < repelRange) {
this.force = Vector.mult(Vector.normalise(sub), this.mass * 0.002)
} else if (dist > attractRange) {
this.force = Vector.mult(Vector.normalise(sub), -this.mass * 0.002)
}
}
}
}
}
}
me.do = function() {
this.checkStatus();
if (this.seePlayer.recall) {
this.do = this.doAwake
//awaken other spawnBosses
for (let i = 0, len = mob.length; i < len; i++) {
if (mob[i].isSpawnBoss && mob[i].spawnID === this.spawnID) mob[i].seePlayer.recall = 1
}
}
};
me.onDeath = function() {
this.isSpawnBoss = false;
let count = 0 //count other cells by id
// console.log(this.spawnID)
for (let i = 0, len = mob.length; i < len; i++) {
if (mob[i].isSpawnBoss && mob[i].spawnID === this.spawnID) count++
}
if (count < 1) { //only drop a power up if this is the last cell
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
tech.deathSpawnsFromBoss -= 0.4
} else {
this.leaveBody = false;
this.isDropPowerUp = false;
}
const spawns = tech.deathSpawns + tech.deathSpawnsFromBoss
const len = Math.min(12, spawns * Math.ceil(Math.random() * simulation.difficulty * spawns))
for (let i = 0; i < len; i++) {
spawn.spawns(this.position.x + (Math.random() - 0.5) * radius * 2.5, this.position.y + (Math.random() - 0.5) * radius * 2.5);
Matter.Body.setVelocity(mob[mob.length - 1], {
x: this.velocity.x + (Math.random() - 0.5) * 10,
y: this.velocity.x + (Math.random() - 0.5) * 10
});
}
}
},
powerUpBoss(x, y, vertices = 9, radius = 130) {
mobs.spawn(x, y, vertices, radius, "transparent");
let me = mob[mob.length - 1];
@@ -596,10 +689,9 @@ const spawn = {
me.seeAtDistance2 = 1000000;
me.accelMag = 0.0005 * simulation.accelScale;
Matter.Body.setDensity(me, 0.00035); //normal is 0.001
me.collisionFilter.mask = cat.bullet | cat.player
me.collisionFilter.mask = cat.bullet | cat.player | cat.body
me.memory = Infinity;
me.seePlayerFreq = 30
me.lockedOn = null;
if (vertices === 9) {
//on primary spawn
@@ -616,17 +708,15 @@ const spawn = {
};
me.onDeath = function() {
this.leaveBody = false;
this.dropPowerUp = false;
if (vertices > 3) {
this.isDropPowerUp = false;
spawn.powerUpBoss(this.position.x, this.position.y, vertices - 1)
Matter.Body.setVelocity(mob[mob.length - 1], {
x: this.velocity.x,
y: this.velocity.y
})
}
for (let i = 0; i < powerUp.length; i++) {
powerUp[i].collisionFilter.mask = cat.map | cat.powerUp
}
for (let i = 0; i < powerUp.length; i++) powerUp[i].collisionFilter.mask = cat.map | cat.powerUp
};
me.do = function() {
this.stroke = `hsl(0,0%,${80+25*Math.sin(simulation.cycle*0.01)}%)`
@@ -829,7 +919,7 @@ const spawn = {
me.seeAtDistance2 = (me.eventHorizon + 400) * (me.eventHorizon + 400); //vision limit is event horizon
me.accelMag = 0.0001 * simulation.accelScale;
me.frictionAir = 0.025;
me.collisionFilter.mask = cat.player | cat.bullet
me.collisionFilter.mask = cat.player | cat.bullet | cat.body
me.memory = Infinity;
Matter.Body.setDensity(me, 0.008); //extra dense //normal is 0.001 //makes effective life much larger
me.do = function() {
@@ -906,7 +996,7 @@ const spawn = {
me.eventHorizon = 1100; //required for black hole
me.seeAtDistance2 = (me.eventHorizon + 1200) * (me.eventHorizon + 1200); //vision limit is event horizon
me.accelMag = 0.00003 * simulation.accelScale;
me.collisionFilter.mask = cat.player | cat.bullet
me.collisionFilter.mask = cat.player | cat.bullet | cat.body
// me.frictionAir = 0.005;
me.memory = 1600;
Matter.Body.setDensity(me, 0.03); //extra dense //normal is 0.001 //makes effective life much larger
@@ -1132,7 +1222,7 @@ const spawn = {
this.fill = `rgba(0,0,0,${0.4+0.6*Math.random()})`
this.stroke = "#014"
this.isShielded = false;
this.dropPowerUp = true;
this.isDropPowerUp = true;
this.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob; //can't touch bullets
ctx.beginPath();
@@ -1160,7 +1250,7 @@ const spawn = {
// ctx.stroke();
} else {
this.isShielded = true;
this.dropPowerUp = false;
this.isDropPowerUp = false;
this.seePlayer.recall = false
this.fill = "transparent"
this.stroke = "transparent"
@@ -1192,7 +1282,7 @@ const spawn = {
},
historyBoss(x, y, radius = 30) {
if (tech.dynamoBotCount > 0) {
spawn.randomLevelBoss(x, y, ["cellBossCulture", "bomberBoss", "powerUpBoss", "orbitalBoss"])
spawn.randomLevelBoss(x, y, ["cellBossCulture", "bomberBoss", "powerUpBoss", "orbitalBoss", "spawnerBossCulture"])
return
}
mobs.spawn(x, y, 0, radius, "transparent");
@@ -1204,7 +1294,7 @@ const spawn = {
me.delayLimit = 60 + Math.floor(60 * Math.random());
me.followDelay = 600 - Math.floor(60 * Math.random())
me.stroke = "transparent"; //used for drawGhost
me.collisionFilter.mask = cat.bullet
me.collisionFilter.mask = cat.bullet | cat.body
me.memory = Infinity
me.onDeath = function() {
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
@@ -1505,83 +1595,85 @@ const spawn = {
}
me.fire = function() {
this.checkStatus();
if (!m.isBodiesAsleep && !m.isCloak && !this.isStunned) {
if (this.isFiring) {
if (this.fireCycle > this.fireDelay) { //fire
this.isFiring = false
this.fireCycle = 0
this.torque += (0.00008 + 0.00007 * Math.random()) * this.inertia * (Math.round(Math.random()) * 2 - 1) //randomly spin around after firing
//is player in beam path
if (Matter.Query.ray([player], this.fireTarget, this.position).length) {
if (!m.isBodiesAsleep) {
if (!m.isCloak && !this.isStunned) {
if (this.isFiring) {
if (this.fireCycle > this.fireDelay) { //fire
this.isFiring = false
this.fireCycle = 0
this.torque += (0.00008 + 0.00007 * Math.random()) * this.inertia * (Math.round(Math.random()) * 2 - 1) //randomly spin around after firing
//is player in beam path
if (Matter.Query.ray([player], this.fireTarget, this.position).length) {
unit = Vector.mult(Vector.normalise(Vector.sub(this.vertices[1], this.position)), this.distanceToPlayer() - 100)
this.fireTarget = Vector.add(this.vertices[1], unit)
}
//damage player if in range
if (Vector.magnitude(Vector.sub(player.position, this.fireTarget)) < this.pulseRadius && m.immuneCycle < m.cycle) {
m.immuneCycle = m.cycle + tech.collisionImmuneCycles; //player is immune to damage
m.damage(0.045 * simulation.dmgScale);
}
simulation.drawList.push({ //add dmg to draw queue
x: this.fireTarget.x,
y: this.fireTarget.y,
radius: this.pulseRadius,
color: "rgba(120,0,255,0.6)",
time: simulation.drawTime
});
ctx.beginPath();
ctx.moveTo(this.vertices[1].x, this.vertices[1].y)
ctx.lineTo(this.fireTarget.x, this.fireTarget.y)
ctx.lineWidth = 20;
ctx.strokeStyle = "rgba(120,0,255,0.2)";
ctx.stroke();
ctx.lineWidth = 4;
ctx.strokeStyle = "rgba(120,0,255,1)";
ctx.stroke();
} else { //delay before firing
this.fireCycle++
//draw explosion outline
ctx.beginPath();
ctx.arc(this.fireTarget.x, this.fireTarget.y, this.pulseRadius, 0, 2 * Math.PI); //* this.fireCycle / this.fireDelay
ctx.fillStyle = "rgba(120,0,255,0.05)";
ctx.fill();
//draw path from mob to explosion
ctx.beginPath();
ctx.moveTo(this.vertices[1].x, this.vertices[1].y)
ctx.lineTo(this.fireTarget.x, this.fireTarget.y)
ctx.setLineDash([40 * Math.random(), 200 * Math.random()]);
ctx.lineWidth = 2;
ctx.strokeStyle = "rgba(120,0,255,0.2)";
ctx.stroke();
ctx.setLineDash([0, 0]);
}
} else { //aim at player
this.fireCycle++
this.fireDir = Vector.normalise(Vector.sub(m.pos, this.position)); //set direction to turn to fire
//rotate towards fireAngle
const angle = this.angle + Math.PI / 2;
const c = Math.cos(angle) * this.fireDir.x + Math.sin(angle) * this.fireDir.y;
const threshold = 0.04;
if (c > threshold) {
this.torque += 0.0000015 * this.inertia;
} else if (c < -threshold) {
this.torque -= 0.0000015 * this.inertia;
} else if (this.fireCycle > 45) { //fire
unit = Vector.mult(Vector.normalise(Vector.sub(this.vertices[1], this.position)), this.distanceToPlayer() - 100)
this.fireTarget = Vector.add(this.vertices[1], unit)
}
//damage player if in range
if (Vector.magnitude(Vector.sub(player.position, this.fireTarget)) < this.pulseRadius && m.immuneCycle < m.cycle) {
m.immuneCycle = m.cycle + tech.collisionImmuneCycles; //player is immune to damage
m.damage(0.045 * simulation.dmgScale);
}
simulation.drawList.push({ //add dmg to draw queue
x: this.fireTarget.x,
y: this.fireTarget.y,
radius: this.pulseRadius,
color: "rgba(120,0,255,0.6)",
time: simulation.drawTime
});
ctx.beginPath();
ctx.moveTo(this.vertices[1].x, this.vertices[1].y)
ctx.lineTo(this.fireTarget.x, this.fireTarget.y)
ctx.lineWidth = 20;
ctx.strokeStyle = "rgba(120,0,255,0.2)";
ctx.stroke();
ctx.lineWidth = 4;
ctx.strokeStyle = "rgba(120,0,255,1)";
ctx.stroke();
} else { //delay before firing
this.fireCycle++
//draw explosion outline
ctx.beginPath();
ctx.arc(this.fireTarget.x, this.fireTarget.y, this.pulseRadius, 0, 2 * Math.PI); //* this.fireCycle / this.fireDelay
ctx.fillStyle = "rgba(120,0,255,0.05)";
ctx.fill();
//draw path from mob to explosion
ctx.beginPath();
ctx.moveTo(this.vertices[1].x, this.vertices[1].y)
ctx.lineTo(this.fireTarget.x, this.fireTarget.y)
ctx.setLineDash([40 * Math.random(), 200 * Math.random()]);
ctx.lineWidth = 2;
ctx.strokeStyle = "rgba(120,0,255,0.2)";
ctx.stroke();
ctx.setLineDash([0, 0]);
}
} else { //aim at player
this.fireCycle++
this.fireDir = Vector.normalise(Vector.sub(m.pos, this.position)); //set direction to turn to fire
//rotate towards fireAngle
const angle = this.angle + Math.PI / 2;
const c = Math.cos(angle) * this.fireDir.x + Math.sin(angle) * this.fireDir.y;
const threshold = 0.04;
if (c > threshold) {
this.torque += 0.0000015 * this.inertia;
} else if (c < -threshold) {
this.torque -= 0.0000015 * this.inertia;
} else if (this.fireCycle > 45) { //fire
unit = Vector.mult(Vector.normalise(Vector.sub(this.vertices[1], this.position)), this.distanceToPlayer() - 100)
this.fireTarget = Vector.add(this.vertices[1], unit)
if (Vector.magnitude(Vector.sub(m.pos, this.fireTarget)) < 1000) { //if's possible for this to be facing 180 degrees away from the player, this makes sure that doesn't occur
Matter.Body.setAngularVelocity(this, 0)
this.fireLockCount = 0
this.isFiring = true
this.fireCycle = 0
if (Vector.magnitude(Vector.sub(m.pos, this.fireTarget)) < 1000) { //if's possible for this to be facing 180 degrees away from the player, this makes sure that doesn't occur
Matter.Body.setAngularVelocity(this, 0)
this.fireLockCount = 0
this.isFiring = true
this.fireCycle = 0
}
}
}
//gently return to starting location
const sub = Vector.sub(this.homePosition, this.position)
const dist = Vector.magnitude(sub)
if (dist > 250) this.force = Vector.mult(Vector.normalise(sub), this.mass * 0.0002)
} else {
this.isFiring = false
}
//gently return to starting location
const sub = Vector.sub(this.homePosition, this.position)
const dist = Vector.magnitude(sub)
if (dist > 250) this.force = Vector.mult(Vector.normalise(sub), this.mass * 0.0002)
} else {
this.isFiring = false
}
};
},
@@ -1622,88 +1714,90 @@ const spawn = {
me.do = function() {
this.seePlayerByLookingAt();
this.checkStatus();
if (!m.isBodiesAsleep && this.seePlayer.recall) {
if (this.isFiring) {
if (this.fireCycle > this.fireDelay) { //fire
if (!this.canSeeTarget()) return
this.isFiring = false
this.fireCycle = 0
this.torque += (0.00002 + 0.0002 * Math.random()) * this.inertia * (Math.round(Math.random()) * 2 - 1) //randomly spin around after firing
//is player in beam path
if (Matter.Query.ray([player], this.fireTarget, this.position).length) {
if (!m.isBodiesAsleep) {
if (this.seePlayer.recall) {
if (this.isFiring) {
if (this.fireCycle > this.fireDelay) { //fire
if (!this.canSeeTarget()) return
this.isFiring = false
this.fireCycle = 0
this.torque += (0.00002 + 0.0002 * Math.random()) * this.inertia * (Math.round(Math.random()) * 2 - 1) //randomly spin around after firing
//is player in beam path
if (Matter.Query.ray([player], this.fireTarget, this.position).length) {
unit = Vector.mult(Vector.normalise(Vector.sub(this.vertices[1], this.position)), this.distanceToPlayer() - 100)
this.fireTarget = Vector.add(this.vertices[1], unit)
}
//damage player if in range
if (Vector.magnitude(Vector.sub(player.position, this.fireTarget)) < this.pulseRadius && m.immuneCycle < m.cycle) {
m.immuneCycle = m.cycle + tech.collisionImmuneCycles; //player is immune to damage
m.damage(0.03 * simulation.dmgScale);
}
simulation.drawList.push({ //add dmg to draw queue
x: this.fireTarget.x,
y: this.fireTarget.y,
radius: this.pulseRadius,
color: "rgba(255,0,100,0.6)",
time: simulation.drawTime
});
ctx.beginPath();
ctx.moveTo(this.vertices[1].x, this.vertices[1].y)
ctx.lineTo(this.fireTarget.x, this.fireTarget.y)
ctx.lineWidth = 20;
ctx.strokeStyle = "rgba(255,0,100,0.2)";
ctx.stroke();
ctx.lineWidth = 4;
ctx.strokeStyle = "rgba(255,0,100,1)";
ctx.stroke();
} else { //delay before firing
this.fireCycle++
if (!(simulation.cycle % 3)) {
if (!this.canSeeTarget()) return //if can't see stop firing
}
//draw explosion outline
ctx.beginPath();
ctx.arc(this.fireTarget.x, this.fireTarget.y, this.pulseRadius, 0, 2 * Math.PI); //* this.fireCycle / this.fireDelay
ctx.fillStyle = "rgba(255,0,100,0.05)";
ctx.fill();
//draw path from mob to explosion
ctx.beginPath();
ctx.moveTo(this.vertices[1].x, this.vertices[1].y)
ctx.lineTo(this.fireTarget.x, this.fireTarget.y)
ctx.setLineDash([40 * Math.random(), 200 * Math.random()]);
ctx.lineWidth = 2;
ctx.strokeStyle = "rgba(255,0,100,0.2)";
ctx.stroke();
ctx.setLineDash([0, 0]);
}
} else { //aim at player
this.fireCycle++
// this.fireDir = ; //set direction to turn to fire
const angle = this.angle + Math.PI / 2;
const dot = Vector.dot({
x: Math.cos(angle),
y: Math.sin(angle)
}, Vector.normalise(Vector.sub(this.seePlayer.position, this.position)))
const threshold = 0.04;
if (dot > threshold) { //rotate towards fireAngle
this.torque += 0.0000015 * this.inertia;
} else if (dot < -threshold) {
this.torque -= 0.0000015 * this.inertia;
} else if (this.fireCycle > 60) { // aim
unit = Vector.mult(Vector.normalise(Vector.sub(this.vertices[1], this.position)), this.distanceToPlayer() - 100)
this.fireTarget = Vector.add(this.vertices[1], unit)
if (!this.canSeeTarget()) return
Matter.Body.setAngularVelocity(this, 0)
this.fireLockCount = 0
this.isFiring = true
this.fireCycle = 0
}
//damage player if in range
if (Vector.magnitude(Vector.sub(player.position, this.fireTarget)) < this.pulseRadius && m.immuneCycle < m.cycle) {
m.immuneCycle = m.cycle + tech.collisionImmuneCycles; //player is immune to damage
m.damage(0.03 * simulation.dmgScale);
}
simulation.drawList.push({ //add dmg to draw queue
x: this.fireTarget.x,
y: this.fireTarget.y,
radius: this.pulseRadius,
color: "rgba(255,0,100,0.6)",
time: simulation.drawTime
});
ctx.beginPath();
ctx.moveTo(this.vertices[1].x, this.vertices[1].y)
ctx.lineTo(this.fireTarget.x, this.fireTarget.y)
ctx.lineWidth = 20;
ctx.strokeStyle = "rgba(255,0,100,0.2)";
ctx.stroke();
ctx.lineWidth = 4;
ctx.strokeStyle = "rgba(255,0,100,1)";
ctx.stroke();
} else { //delay before firing
this.fireCycle++
if (!(simulation.cycle % 3)) {
if (!this.canSeeTarget()) return //if can't see stop firing
}
//draw explosion outline
ctx.beginPath();
ctx.arc(this.fireTarget.x, this.fireTarget.y, this.pulseRadius, 0, 2 * Math.PI); //* this.fireCycle / this.fireDelay
ctx.fillStyle = "rgba(255,0,100,0.05)";
ctx.fill();
//draw path from mob to explosion
ctx.beginPath();
ctx.moveTo(this.vertices[1].x, this.vertices[1].y)
ctx.lineTo(this.fireTarget.x, this.fireTarget.y)
ctx.setLineDash([40 * Math.random(), 200 * Math.random()]);
ctx.lineWidth = 2;
ctx.strokeStyle = "rgba(255,0,100,0.2)";
ctx.stroke();
ctx.setLineDash([0, 0]);
}
} else { //aim at player
this.fireCycle++
// this.fireDir = ; //set direction to turn to fire
const angle = this.angle + Math.PI / 2;
const dot = Vector.dot({
x: Math.cos(angle),
y: Math.sin(angle)
}, Vector.normalise(Vector.sub(this.seePlayer.position, this.position)))
const threshold = 0.04;
if (dot > threshold) { //rotate towards fireAngle
this.torque += 0.0000015 * this.inertia;
} else if (dot < -threshold) {
this.torque -= 0.0000015 * this.inertia;
} else if (this.fireCycle > 60) { // aim
unit = Vector.mult(Vector.normalise(Vector.sub(this.vertices[1], this.position)), this.distanceToPlayer() - 100)
this.fireTarget = Vector.add(this.vertices[1], unit)
if (!this.canSeeTarget()) return
Matter.Body.setAngularVelocity(this, 0)
this.fireLockCount = 0
this.isFiring = true
this.fireCycle = 0
}
//gently return to starting location
const sub = Vector.sub(this.homePosition, this.position)
const dist = Vector.magnitude(sub)
if (dist > 350) this.force = Vector.mult(Vector.normalise(sub), this.mass * 0.0002)
} else {
this.isFiring = false
}
//gently return to starting location
const sub = Vector.sub(this.homePosition, this.position)
const dist = Vector.magnitude(sub)
if (dist > 350) this.force = Vector.mult(Vector.normalise(sub), this.mass * 0.0002)
} else {
this.isFiring = false
}
};
},
@@ -2054,7 +2148,7 @@ const spawn = {
me.alpha = 1; //used in drawGhost
me.canTouchPlayer = false; //used in drawGhost
// me.leaveBody = false;
me.collisionFilter.mask = cat.bullet
me.collisionFilter.mask = cat.bullet | cat.body
me.showHealthBar = false;
me.memory = 480;
me.do = function() {
@@ -2165,7 +2259,7 @@ const spawn = {
me.memory = Infinity;
// me.memory = 300;
// Matter.Body.setDensity(me, 0.0015); //extra dense //normal is 0.001
me.collisionFilter.mask = cat.player | cat.bullet
me.collisionFilter.mask = cat.player | cat.bullet | cat.body
spawn.shield(me, x, y, 1);
@@ -2271,7 +2365,7 @@ const spawn = {
me.frictionAir = 0;
me.restitution = 0.8;
me.leaveBody = false;
me.dropPowerUp = false;
me.isDropPowerUp = false;
me.showHealthBar = false;
me.collisionFilter.category = cat.mobBullet;
@@ -2322,7 +2416,7 @@ const spawn = {
me.frictionAir = 0;
me.restitution = 1;
me.leaveBody = false;
me.dropPowerUp = false;
me.isDropPowerUp = false;
me.showHealthBar = false;
me.collisionFilter.category = cat.mobBullet;
me.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet;
@@ -2460,14 +2554,14 @@ const spawn = {
me.frictionAir = 0;
me.restitution = 0;
me.leaveBody = false;
me.dropPowerUp = false;
me.isDropPowerUp = false;
me.showHealthBar = false;
me.collisionFilter.category = cat.mobBullet;
me.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet;
me.do = function() {
this.timeLimit();
if (Matter.Query.collides(this, map).length > 0 || Matter.Query.collides(this, body).length > 0 && this.speed < 3) {
this.dropPowerUp = false;
this.isDropPowerUp = false;
this.death(); //death with no power up
}
};
@@ -2552,6 +2646,7 @@ const spawn = {
me.frictionStatic = 0;
me.friction = 0;
me.frictionAir = 0.5;
me.homePosition = { x: x, y: y };
spawn.shield(me, x, y, 1);
spawn.spawnOrbitals(me, radius + 50 + 200 * Math.random())
@@ -2582,10 +2677,9 @@ const spawn = {
this.cycle = 0
ctx.beginPath();
for (let i = 0; i < mob.length; i++) {
if (!mob[i].isShielded && !mob[i].shield && mob[i].dropPowerUp && mob[i].alive) {
if (!mob[i].isShielded && !mob[i].shield && mob[i].isDropPowerUp && mob[i].alive) {
ctx.moveTo(this.position.x, this.position.y)
ctx.lineTo(mob[i].position.x, mob[i].position.y)
spawn.shield(mob[i], mob[i].position.x, mob[i].position.y, 1, true);
}
}
@@ -2593,6 +2687,10 @@ const spawn = {
// ctx.lineCap = "round";
ctx.strokeStyle = "rgba(200,200,255,0.9)"
ctx.stroke();
//return to starting location
const sub = Vector.sub(this.homePosition, this.position)
const dist = Vector.magnitude(sub)
if (dist > 350) this.force = Vector.mult(Vector.normalise(sub), this.mass * 0.05)
}
}
};
@@ -2690,7 +2788,7 @@ const spawn = {
me.frictionAir = 0.01 //* (0.8 + 0.4 * Math.random());
me.restitution = 0.5;
me.leaveBody = false;
me.dropPowerUp = false;
me.isDropPowerUp = false;
me.showHealthBar = false;
me.collisionFilter.category = cat.mobBullet;
me.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet;
@@ -2706,7 +2804,7 @@ const spawn = {
let me = mob[mob.length - 1];
me.g = 0.0004; //required if using 'gravity'
me.leaveBody = false;
// me.dropPowerUp = false;
// me.isDropPowerUp = false;
me.onDeath = function() { //run this function on death
for (let i = 0; i < Math.ceil(this.mass * 0.15 + Math.random() * 2.5); ++i) {
spawn.spawns(this.position.x + (Math.random() - 0.5) * radius * 2.5, this.position.y + (Math.random() - 0.5) * radius * 2.5);
@@ -2724,25 +2822,33 @@ const spawn = {
this.attraction();
};
},
spawns(x, y, radius = 15 + Math.ceil(Math.random() * 5)) {
spawns(x, y, radius = 15) {
mobs.spawn(x, y, 4, radius, "rgb(255,0,0)");
let me = mob[mob.length - 1];
me.onHit = function() {
//run this function on hitting player
this.explode();
};
// me.stroke = "transparent"
me.collisionFilter.mask = cat.player | cat.bullet | cat.body | cat.map
me.showHealthBar = false;
Matter.Body.setDensity(me, 0.0005); //normal is 0.001
me.g = 0.0001; //required if using 'gravity'
me.accelMag = 0.0003 * simulation.accelScale;
me.accelMag = 0.00008 * simulation.accelScale;
me.memory = 30;
me.leaveBody = false;
me.isDropPowerUp = false;
me.seePlayerFreq = Math.round((80 + 50 * Math.random()) * simulation.lookFreqScale);
me.frictionAir = 0.002;
me.frictionAir = 0.004;
me.do = function() {
this.gravity();
this.seePlayerCheck();
this.checkStatus();
this.attraction();
// this.alwaysSeePlayer();
// this.checkStatus();
// this.attraction();
};
},
// exploder(x, y, radius = 40 + Math.ceil(Math.random() * 50)) {
@@ -2859,7 +2965,7 @@ const spawn = {
// //run this function on hitting player
// this.explode();
// };
me.collisionFilter.mask = cat.bullet | cat.player | cat.mob
me.collisionFilter.mask = cat.bullet | cat.player | cat.mob | cat.body
me.accelMag = 0.0004 * simulation.accelScale;
me.leaveBody = false;
me.frictionAir = 0.02;
@@ -2943,7 +3049,7 @@ const spawn = {
this.fill = `rgba(220,220,255,${0.3 + 0.6 *this.health})`
};
me.leaveBody = false;
me.dropPowerUp = false;
me.isDropPowerUp = false;
me.showHealthBar = false;
me.shieldTargetID = target.id
@@ -3000,7 +3106,7 @@ const spawn = {
}
};
me.leaveBody = false;
me.dropPowerUp = false;
me.isDropPowerUp = false;
me.showHealthBar = false;
mob[mob.length - 1] = mob[mob.length - 1 - nodes];
mob[mob.length - 1 - nodes] = me;
@@ -3023,7 +3129,7 @@ const spawn = {
me.stroke = "transparent";
Matter.Body.setDensity(me, 0.1); //normal is 0.001
me.leaveBody = false;
me.dropPowerUp = false;
me.isDropPowerUp = false;
me.showHealthBar = false;
// me.isShielded = true
me.collisionFilter.category = cat.mobBullet;
@@ -3062,7 +3168,7 @@ const spawn = {
me.memory = Infinity;
me.frictionAir = 0.01;
me.accelMag = 0.00004 * simulation.accelScale;
me.collisionFilter.mask = cat.player | cat.bullet
me.collisionFilter.mask = cat.player | cat.bullet | cat.body
spawn.shield(me, x, y, 1);
const rangeInnerVsOuter = Math.random()
@@ -3240,7 +3346,7 @@ const spawn = {
me.frictionStatic = 1;
me.friction = 1;
me.frictionAir = 0.01;
me.dropPowerUp = false;
me.isDropPowerUp = false;
me.showHealthBar = false;
me.do = function() {
@@ -3307,7 +3413,7 @@ const spawn = {
me.frictionStatic = 1;
me.friction = 1;
me.frictionAir = 0.01;
me.dropPowerUp = false;
me.isDropPowerUp = false;
me.showHealthBar = false;
me.do = function() {
@@ -3357,7 +3463,7 @@ const spawn = {
me.frictionStatic = 1;
me.friction = 1;
me.frictionAir = 0.01;
me.dropPowerUp = false;
me.isDropPowerUp = false;
me.showHealthBar = false;
me.do = function() {
@@ -3406,7 +3512,7 @@ const spawn = {
// me.frictionStatic = 1;
// me.friction = 1;
me.frictionAir = 0.01;
me.dropPowerUp = false;
me.isDropPowerUp = false;
me.showHealthBar = false;
me.do = function() {
@@ -3455,7 +3561,7 @@ const spawn = {
// me.frictionStatic = 1;
// me.friction = 1;
me.frictionAir = 0.01;
me.dropPowerUp = false;
me.isDropPowerUp = false;
me.showHealthBar = false;
me.do = function() {

View File

@@ -154,7 +154,7 @@
if (tech.is100Duplicate && tech.duplicationChance() > 0.99) {
tech.is100Duplicate = false
const range = 1000
const bossOptions = ["historyBoss", "cellBossCulture", "bomberBoss", "powerUpBoss", "orbitalBoss"]
const bossOptions = ["historyBoss", "cellBossCulture", "bomberBoss", "powerUpBoss", "orbitalBoss", "spawnerBossCulture"]
spawn.randomLevelBoss(m.pos.x + range, m.pos.y, bossOptions);
spawn.randomLevelBoss(m.pos.x, m.pos.y + range, bossOptions);
spawn.randomLevelBoss(m.pos.x - range, m.pos.y, bossOptions);
@@ -230,7 +230,7 @@
},
{
name: "active cooling",
description: "<strong>17%</strong> decreased <strong><em>delay</em></strong> after firing<br>for each <strong class='color-g'>gun</strong> in your inventory",
description: "<strong>14%</strong> decreased <strong><em>delay</em></strong> after firing<br>for each <strong class='color-g'>gun</strong> in your inventory",
maxCount: 1,
count: 0,
frequency: 2,
@@ -2641,13 +2641,13 @@
},
requires: "below 100% duplication chance, below level 5, not determinism",
effect() {
// tech.cancelCount = 0
tech.isCancelDuplication = true
tech.cancelCount = 0
simulation.draw.powerUp = simulation.draw.powerUpBonus //change power up draw
},
remove() {
tech.isCancelDuplication = false
// tech.cancelCount = 0
tech.isCancelDuplication = false
if (tech.duplicationChance() === 0) simulation.draw.powerUp = simulation.draw.powerUpNormal
}
},
@@ -5015,7 +5015,7 @@
effect() {
setInterval(() => {
for (let i = 0; i < mob.length; i++) {
if (!mob[i].isShielded && !mob[i].shield && mob[i].dropPowerUp) spawn.shield(mob[i], mob[i].position.x, mob[i].position.y, 1, true);
if (!mob[i].isShielded && !mob[i].shield && mob[i].isDropPowerUp) spawn.shield(mob[i], mob[i].position.x, mob[i].position.y, 1, true);
}
}, 5000); //every 5 seconds
},
@@ -5048,7 +5048,7 @@
},
{
name: "panopticon",
description: "<strong style='color: #f55;'>experiment:</strong> mobs can see you all the time",
description: "<strong style='color: #f55;'>experiment:</strong> mobs can always see you",
maxCount: 1,
count: 0,
frequency: 0,
@@ -5062,7 +5062,7 @@
effect() {
setInterval(() => {
for (let i = 0; i < mob.length; i++) {
if (!mob[i].shield && mob[i].dropPowerUp) {
if (!mob[i].shield && mob[i].isDropPowerUp) {
mob[i].locatePlayer()
mob[i].seePlayer.yes = true;
}
@@ -5071,6 +5071,26 @@
},
remove() {}
},
{
name: "decomposers",
description: "<strong style='color: #f55;'>experiment:</strong> after they die<br>mobs leave behind spawns",
maxCount: 1,
count: 0,
frequency: 0,
isBadRandomOption: true,
isExperimentalMode: true,
allowed() {
return build.isExperimentSelection
},
requires: "",
effect() {
tech.deathSpawns = 0.2
},
remove() {
tech.deathSpawns = 0
}
},
//**************************************************
//************************************************** JUNK
//************************************************** tech
@@ -5093,9 +5113,29 @@
// },
// remove() {}
// },
{
name: "decomposers",
description: "after they die <strong>mobs</strong> leave behind <strong>spawns</strong>",
maxCount: 1,
count: 0,
frequency: 0,
isExperimentHide: true,
isNonRefundable: true,
isJunk: true,
allowed() {
return build.isExperimentSelection
},
requires: "",
effect() {
tech.deathSpawns = 0.2
},
remove() {
tech.deathSpawns = 0
}
},
{
name: "panopticon",
description: "<strong>experiment:</strong> mobs can see you all the time",
description: "<strong>mobs</strong> can always see you",
maxCount: 1,
count: 0,
frequency: 0,
@@ -5109,7 +5149,7 @@
effect() {
setInterval(() => {
for (let i = 0; i < mob.length; i++) {
if (!mob[i].shield && mob[i].dropPowerUp) {
if (!mob[i].shield && mob[i].isDropPowerUp) {
mob[i].locatePlayer()
mob[i].seePlayer.yes = true;
}
@@ -6365,5 +6405,6 @@
isNoHeals: null,
frequencyResonance: null,
isAlwaysFire: null,
isDroneRespawn: null
isDroneRespawn: null,
deathSpawns: null
}