spawns
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:
36
js/bullet.js
36
js/bullet.js
@@ -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;
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -331,7 +331,8 @@ const build = {
|
||||
// text += `<div class="pause-grid-module"><div class="grid-title"><div class="circle-grid junk"></div> ${tech.tech[i].name} ${isCount}</div>${tech.tech[i].description}</div></div>`
|
||||
techID.innerHTML = `<div class="grid-title"><div class="circle-grid junk"></div> ${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> ${tech.tech[i].name} ${isCount}</div>${tech.tech[i].description}</div>`
|
||||
}
|
||||
|
||||
63
js/level.js
63
js/level.js
@@ -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();
|
||||
|
||||
35
js/mob.js
35
js/mob.js
@@ -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) {
|
||||
|
||||
17
js/player.js
17
js/player.js
@@ -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"
|
||||
|
||||
@@ -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();
|
||||
|
||||
482
js/spawn.js
482
js/spawn.js
@@ -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() {
|
||||
|
||||
61
js/tech.js
61
js/tech.js
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user