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

BIN
.DS_Store vendored

Binary file not shown.

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
}

View File

@@ -1,16 +1,19 @@
******************************************************** NEXT PATCH ********************************************************
experiment and junk: panopticon - mobs can see you all the time
experiment and junk tech: decomposers - mobs leave behind spawns when they die
scrap bots now have a 33% chance to spawn for 10 seconds after killing a mob
(was 20% chance for 20 seconds)
tech: scrap refit - killing a mob resets your functional scrap bots back to 10 seconds of operation
new levelBoss - a cluster of larger spawns
while it's alive all mobs other leave behind spawns
several damage tech have reduced damage by about 10%
spores do 20% more damage, but last 1 second shorter
added block collisions to most no collide mobs
(this should buff block throwing and pilot wave)
******************************************************** BUGS ********************************************************
Copied build urls broke. You get the guns but none of the tech
spawns are forming node groups, but why??
you have to press z once to get copy to work for simulation.enableConstructMode() sometimes
not sure how to reproduce, but it happens often on the first draw
@@ -39,6 +42,34 @@ fix door.isOpen actually meaning isClosed?
******************************************************** TODO ********************************************************
tech plasma field - plasma field becomes an aoe damage field with the same radius
200% more energy drain, 100% more damage
draw a square (or two) that rapidly spins
blocking produces ice-IX
at the block location?
how to get bullets to not hit the blocked mob
spawn at player head?
only applies to blocking with a cool down
nano-scale?
standing wave harmonics
maybe just a chance to proc for perfect diamagnetism
laser beam splitter should only increase by 1,2,3,4 not 1,3,5
tech field: while _____ is active take 100% more harm and do 100% more damage
while firing
or while plasma field is active
make a boss that increases tech.deathSpawns while it is alive
tech.deathSpawns += 2
on death tech.deathSpawns -= 2
how to make it clear that the bos is producing the spawns?
boss is make of many spawn-like mobs
but they need to have a different color from spawns
similar to how cellBoss works
with stronger flocking/attracting forces
quantum foam: hold fire to charge up foam, release fire to let go an amount relative to hold long you held fire
foam gun fires a bullet that tracks how long mouse is down
when mouse is up it streams out a hose of foam based on how long foam was down