blockBoss
blockBoss: new boss based on work by TheShwarma (3x chance to randomly see blockBoss until next patch) it's over powered, I'll probably nerf it next patch, but I want to get some feedback first on how to nerf it hint: if you kill the boss all the mobBlocks turn back into blocks very very small blocks are slightly limited in how fast they can be thrown they were moving so fast they would miss their target sometimes tech: energy conservation gives 5% energy back (was 6%) tech: arsenal requires at least 3 guns in your inventory tech: active cooling requires at least 2 guns in your inventory several bug fixes
This commit is contained in:
@@ -3080,13 +3080,13 @@ const b = {
|
||||
minDmgSpeed: 2,
|
||||
lookFrequency: 27 + Math.ceil(6 * Math.random()),
|
||||
cd: 0,
|
||||
delay: 80,
|
||||
delay: 70,
|
||||
range: 70 + 3 * b.totalBots(),
|
||||
endCycle: Infinity,
|
||||
classType: "bullet",
|
||||
collisionFilter: {
|
||||
category: cat.bullet,
|
||||
mask: b.totalBots() < 50 ? cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet | cat.mobShield : cat.map | cat.body | cat.mob | cat.mobBullet | cat.mobShield //if over 50 bots, they no longer collide with each other
|
||||
mask: b.totalBots() < 50 ? (cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet | cat.mobShield) : (cat.map | cat.body | cat.mob | cat.mobBullet | cat.mobShield) //if over 50 bots, they no longer collide with each other
|
||||
},
|
||||
beforeDmg() {},
|
||||
onEnd() {},
|
||||
@@ -5055,7 +5055,7 @@ const b = {
|
||||
|
||||
m.fireCDcycle = Infinity //can't fire until mouse is released
|
||||
const previousCharge = this.charge
|
||||
let smoothRate = (m.crouch ? 0.98 : 0.985) * (0.98 + 0.02 * b.fireCDscale) //small b.fireCDscale = faster shots, b.fireCDscale=1 = normal shot, big b.fireCDscale = slower chot
|
||||
let smoothRate = Math.min(0.998, (m.crouch ? 0.98 : 0.985) * (0.98 + 0.02 * b.fireCDscale)) //small b.fireCDscale = faster shots, b.fireCDscale=1 = normal shot, big b.fireCDscale = slower chot
|
||||
this.charge = this.charge * smoothRate + 1 - smoothRate
|
||||
m.energy += (this.charge - previousCharge) * (tech.isRailEnergyGain ? 1 : -0.33) //energy drain is proportional to charge gained, but doesn't stop normal m.fieldRegen
|
||||
//draw targeting
|
||||
|
||||
19
js/level.js
19
js/level.js
@@ -109,12 +109,19 @@ const level = {
|
||||
},
|
||||
custom() {},
|
||||
customTopLayer() {},
|
||||
setDifficulty() {
|
||||
simulation.difficulty = 0
|
||||
b.dmgScale = 1; //damage done by player decreases each level
|
||||
simulation.accelScale = 1 //mob acceleration increases each level
|
||||
simulation.CDScale = 1 //mob CD time decreases each level
|
||||
simulation.dmgScale = 0.41 * simulation.difficulty //damage done by mobs increases each level
|
||||
simulation.healScale = 1 / (1 + simulation.difficulty * 0.055) //a higher denominator makes for lower heals // m.health += heal * simulation.healScale;
|
||||
},
|
||||
difficultyIncrease(num = 1) {
|
||||
for (let i = 0; i < num; i++) {
|
||||
simulation.difficulty++
|
||||
b.dmgScale *= 0.914; //damage done by player decreases each level
|
||||
if (simulation.accelScale < 5) simulation.accelScale *= 1.02 //mob acceleration increases each level
|
||||
if (simulation.lookFreqScale > 0.2) simulation.lookFreqScale *= 0.98 //mob cycles between looks decreases each level
|
||||
if (simulation.CDScale > 0.2) simulation.CDScale *= 0.97 //mob CD time decreases each level
|
||||
}
|
||||
simulation.dmgScale = 0.41 * simulation.difficulty //damage done by mobs increases each level
|
||||
@@ -125,7 +132,6 @@ const level = {
|
||||
simulation.difficulty--
|
||||
b.dmgScale /= 0.914; //damage done by player decreases each level
|
||||
if (simulation.accelScale > 0.2) simulation.accelScale /= 1.02 //mob acceleration increases each level
|
||||
if (simulation.lookFreqScale < 5) simulation.lookFreqScale /= 0.98 //mob cycles between looks decreases each level
|
||||
if (simulation.CDScale < 5) simulation.CDScale /= 0.97 //mob CD time decreases each level
|
||||
}
|
||||
if (simulation.difficulty < 1) simulation.difficulty = 0;
|
||||
@@ -2266,12 +2272,13 @@ const level = {
|
||||
spawn.mapRect(5050, -100, 50, 150);
|
||||
spawn.mapRect(4850, -275, 50, 175);
|
||||
// level.difficultyIncrease(30) //30 is near max on hard //60 is near max on why
|
||||
spawn.starter(1900, -500, 200) //big boy
|
||||
// spawn.spiderBoss(1900, -500)
|
||||
// spawn.starter(1900, -500, 200) //big boy
|
||||
spawn.necroBoss(1900, -500)
|
||||
// for (let i = 0; i < 10; ++i) spawn.bodyRect(1600 + 5, -500, 30, 40);
|
||||
// spawn.laserBombingBoss(1900, -500)
|
||||
// for (let i = 0; i < 5; i++) spawn.focuser(1900, -500)
|
||||
|
||||
// spawn.sniper(1900, -500)
|
||||
// spawn.blockGroup(1900, -500)
|
||||
// spawn.grenadier(1900, -500)
|
||||
// spawn.sneaker(1900, -500)
|
||||
// spawn.shield(mob[mob.length - 1], 1900, -500, 1);
|
||||
@@ -2286,7 +2293,7 @@ const level = {
|
||||
// spawn.powerUpBoss(1600, -500)
|
||||
// spawn.cellBossCulture(1600, -500)
|
||||
// spawn.laserTargetingBoss(1600, -500)
|
||||
// spawn.grenadierBoss(1200, -500)
|
||||
// spawn.striker(1200, -500)
|
||||
|
||||
// spawn.nodeGroup(1200, -500, "grenadier")
|
||||
// spawn.snakeBoss(1200, -500)
|
||||
|
||||
@@ -268,7 +268,7 @@ const mobs = {
|
||||
gravity() {
|
||||
this.force.y += this.mass * this.g;
|
||||
},
|
||||
seePlayerFreq: Math.floor((30 + 30 * Math.random()) * simulation.lookFreqScale), //how often NPC checks to see where player is, lower numbers have better vision
|
||||
seePlayerFreq: Math.floor(30 + 30 * Math.random()), //how often NPC checks to see where player is, lower numbers have better vision
|
||||
foundPlayer() {
|
||||
this.locatePlayer();
|
||||
if (!this.seePlayer.yes) {
|
||||
@@ -759,11 +759,6 @@ const mobs = {
|
||||
attraction() {
|
||||
//accelerate towards the player
|
||||
if (this.seePlayer.recall) {
|
||||
// && dx * dx + dy * dy < 2000000) {
|
||||
// const forceMag = this.accelMag * this.mass;
|
||||
// const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x);
|
||||
// this.force.x += forceMag * Math.cos(angle);
|
||||
// this.force.y += forceMag * Math.sin(angle);
|
||||
const force = Vector.mult(Vector.normalise(Vector.sub(this.seePlayer.position, this.position)), this.accelMag * this.mass)
|
||||
this.force.x += force.x;
|
||||
this.force.y += force.y;
|
||||
|
||||
@@ -389,12 +389,10 @@ const m = {
|
||||
},
|
||||
death() {
|
||||
if (tech.isImmortal) { //if player has the immortality buff, spawn on the same level with randomized damage
|
||||
|
||||
//remove immortality tech
|
||||
// for (let i = 0; i < tech.tech.length; i++) {
|
||||
// if (tech.tech[i].name === "quantum immortality") tech.removeTech(i)
|
||||
// }
|
||||
|
||||
simulation.wipe = function() { //set wipe to have trails
|
||||
ctx.fillStyle = "rgba(255,255,255,0)";
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
@@ -480,7 +478,7 @@ const m = {
|
||||
setMaxHealth() {
|
||||
m.maxHealth = m.baseHealth + tech.extraMaxHealth + tech.isFallingDamage //+ tech.bonusHealth
|
||||
document.getElementById("health-bg").style.width = `${Math.floor(300*m.maxHealth)}px`
|
||||
simulation.makeTextLog(`<span class='color-var'>m</span>.<span class='color-h'>maxHealth</span> <span class='color-symbol'>=</span> ${m.maxHealth.toFixed(3)}`)
|
||||
simulation.makeTextLog(`<span class='color-var'>m</span>.<span class='color-h'>maxHealth</span> <span class='color-symbol'>=</span> ${m.maxHealth.toFixed(2)}`)
|
||||
if (m.health > m.maxHealth) m.health = m.maxHealth;
|
||||
m.displayHealth();
|
||||
},
|
||||
@@ -655,13 +653,12 @@ const m = {
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
}
|
||||
}, 3000);
|
||||
return;
|
||||
} else { //death
|
||||
m.health = 0;
|
||||
m.energy = 0;
|
||||
m.death();
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
dmg *= m.harmReduction()
|
||||
@@ -1161,7 +1158,7 @@ const m = {
|
||||
|
||||
const charge = Math.min(m.throwCharge / 5, 1)
|
||||
//***** scale throw speed with the first number, 80 *****
|
||||
let speed = 80 * charge * Math.min(1, 0.8 / Math.pow(m.holdingTarget.mass, 0.25));
|
||||
let speed = 80 * charge * Math.min(0.85, 0.8 / Math.pow(m.holdingTarget.mass, 0.25));
|
||||
|
||||
if (Matter.Query.collides(m.holdingTarget, map).length !== 0) {
|
||||
speed *= 0.7 //drop speed by 30% if touching map
|
||||
|
||||
@@ -130,7 +130,6 @@ const simulation = {
|
||||
healScale: 1,
|
||||
accelScale: null, //set in levels.setDifficulty
|
||||
CDScale: null, //set in levels.setDifficulty
|
||||
lookFreqScale: null, //set in levels.setDifficulty
|
||||
isNoPowerUps: false,
|
||||
// dropFPS(cap = 40, time = 15) {
|
||||
// simulation.fpsCap = cap
|
||||
@@ -541,10 +540,6 @@ const simulation = {
|
||||
if (simulation.onTitlePage) requestAnimationFrame(cycle);
|
||||
}
|
||||
requestAnimationFrame(cycle)
|
||||
|
||||
|
||||
|
||||
|
||||
}, 1000);
|
||||
},
|
||||
startGame(isBuildRun = false) {
|
||||
@@ -617,6 +612,7 @@ const simulation = {
|
||||
tech.plasmaBotCount = 0;
|
||||
tech.missileBotCount = 0;
|
||||
|
||||
simulation.isChoosing = false;
|
||||
b.setFireMethod()
|
||||
b.setFireCD();
|
||||
// simulation.updateTechHUD();
|
||||
@@ -641,20 +637,25 @@ const simulation = {
|
||||
|
||||
level.onLevel = 0;
|
||||
level.levelsCleared = 0;
|
||||
//resetting difficulty
|
||||
simulation.dmgScale = 0; //increases in level.difficultyIncrease
|
||||
b.dmgScale = 1; //decreases in level.difficultyIncrease
|
||||
simulation.accelScale = 1;
|
||||
simulation.lookFreqScale = 1;
|
||||
simulation.CDScale = 1;
|
||||
simulation.difficulty = 0;
|
||||
simulation.difficultyMode = Number(document.getElementById("difficulty-select").value)
|
||||
build.isExperimentSelection = false;
|
||||
|
||||
//resetting difficulty
|
||||
// simulation.difficulty = 0;
|
||||
level.setDifficulty()
|
||||
simulation.difficultyMode = Number(document.getElementById("difficulty-select").value)
|
||||
|
||||
build.isExperimentSelection = false;
|
||||
simulation.clearNow = true;
|
||||
document.getElementById("text-log").style.opacity = 0;
|
||||
document.getElementById("fade-out").style.opacity = 0;
|
||||
document.title = "n-gon";
|
||||
// simulation.makeTextLog(`input.key.up<span class='color-symbol'>:</span> ["<span class='color-text'>${input.key.up}</span>", "<span class='color-text'>ArrowUp</span>"]`);
|
||||
// simulation.makeTextLog(`input.key.left<span class='color-symbol'>:</span> ["<span class='color-text'>${input.key.left}</span>", "<span class='color-text'>ArrowLeft</span>"]`);
|
||||
// simulation.makeTextLog(`input.key.down<span class='color-symbol'>:</span> ["<span class='color-text'>${input.key.down}</span>", "<span class='color-text'>ArrowDown</span>"]`);
|
||||
// simulation.makeTextLog(`input.key.right<span class='color-symbol'>:</span> ["<span class='color-text'>${input.key.right}</span>", "<span class='color-text'>ArrowRight</span>"]`);
|
||||
simulation.makeTextLog(`<span class='color-var'>const</span> engine <span class='color-symbol'>=</span> Engine.create(); <em>//simulation begin</em>`);
|
||||
simulation.makeTextLog(`engine.timing.timeScale <span class='color-symbol'>=</span> 1`);
|
||||
simulation.makeTextLog(`<span class='color-var'>m</span>.setField("<span class='color-text'>${m.fieldUpgrades[m.fieldMode].name}</span>")`);
|
||||
// simulation.makeTextLog(`input.key.field<span class='color-symbol'>:</span> ["<span class='color-text'>${input.key.field}</span>", "<span class='color-text'>MouseRight</span>"]`);
|
||||
|
||||
document.getElementById("health").style.display = "inline"
|
||||
document.getElementById("health-bg").style.display = "inline"
|
||||
@@ -668,6 +669,7 @@ const simulation = {
|
||||
//set to default field
|
||||
tech.healMaxEnergyBonus = 0
|
||||
m.setMaxEnergy();
|
||||
m.energy = 0
|
||||
m.fieldMode = 0;
|
||||
// simulation.makeTextLog(`${simulation.SVGrightMouse}<strong style='font-size:30px;'> ${m.fieldUpgrades[m.fieldMode].name}</strong><br><span class='faded'></span><br>${m.fieldUpgrades[m.fieldMode].description}`, 600);
|
||||
// simulation.makeTextLog(`
|
||||
@@ -681,28 +683,6 @@ const simulation = {
|
||||
// <br><span class='color-var'>m</span>.field.description <span class='color-symbol'>=</span> "<span class='color-text'>${m.fieldUpgrades[m.fieldMode].description}</span>"
|
||||
// `, 800);
|
||||
|
||||
|
||||
let delay = 500
|
||||
const step = 150
|
||||
setTimeout(function() {
|
||||
simulation.makeTextLog(`input.key.up<span class='color-symbol'>:</span> ["<span class='color-text'>${input.key.up}</span>", "<span class='color-text'>ArrowUp</span>"]`);
|
||||
}, delay += step);
|
||||
setTimeout(function() {
|
||||
simulation.makeTextLog(`input.key.left<span class='color-symbol'>:</span> ["<span class='color-text'>${input.key.left}</span>", "<span class='color-text'>ArrowLeft</span>"]`);
|
||||
}, delay += step);
|
||||
setTimeout(function() {
|
||||
simulation.makeTextLog(`input.key.down<span class='color-symbol'>:</span> ["<span class='color-text'>${input.key.down}</span>", "<span class='color-text'>ArrowDown</span>"]`);
|
||||
}, delay += step);
|
||||
setTimeout(function() {
|
||||
simulation.makeTextLog(`input.key.right<span class='color-symbol'>:</span> ["<span class='color-text'>${input.key.right}</span>", "<span class='color-text'>ArrowRight</span>"]`);
|
||||
}, delay += step);
|
||||
setTimeout(function() {
|
||||
simulation.makeTextLog(`<br><span class='color-var'>m</span>.fieldMode <span class='color-symbol'>=</span> "<span class='color-text'>${m.fieldUpgrades[m.fieldMode].name}</span>"`);
|
||||
}, delay += step);
|
||||
setTimeout(function() {
|
||||
simulation.makeTextLog(`input.key.field<span class='color-symbol'>:</span> ["<span class='color-text'>${input.key.field}</span>", "<span class='color-text'>MouseRight</span>"]`);
|
||||
}, delay += step);
|
||||
|
||||
m.setField(m.fieldMode)
|
||||
// m.energy = 0;
|
||||
//exit testing
|
||||
@@ -718,7 +698,6 @@ const simulation = {
|
||||
simulation.fpsInterval = 1000 / simulation.fpsCap;
|
||||
simulation.then = Date.now();
|
||||
requestAnimationFrame(cycle); //starts game loop
|
||||
|
||||
},
|
||||
clearTimeouts() {
|
||||
let id = window.setTimeout(function() {}, 0);
|
||||
|
||||
244
js/spawn.js
244
js/spawn.js
@@ -1,7 +1,7 @@
|
||||
//main object for spawning things in a level
|
||||
const spawn = {
|
||||
nonCollideBossList: ["cellBossCulture", "bomberBoss", "powerUpBoss", "orbitalBoss", "spawnerBossCulture", "growBossCulture"],
|
||||
randomLevelBoss(x, y, options = ["shieldingBoss", "orbitalBoss", "historyBoss", "shooterBoss", "cellBossCulture", "bomberBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss", "powerUpBoss", "snakeBoss", "streamBoss", "pulsarBoss", "spawnerBossCulture", "grenadierBoss", "growBossCulture", "blinkBoss", "snakeSpitBoss", "laserBombingBoss"]) {
|
||||
randomLevelBoss(x, y, options = ["shieldingBoss", "orbitalBoss", "historyBoss", "shooterBoss", "cellBossCulture", "bomberBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss", "powerUpBoss", "snakeBoss", "streamBoss", "pulsarBoss", "spawnerBossCulture", "grenadierBoss", "growBossCulture", "blinkBoss", "snakeSpitBoss", "laserBombingBoss", "blockBoss", "blockBoss", "blockBoss"]) {
|
||||
// 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)
|
||||
},
|
||||
@@ -54,7 +54,7 @@ const spawn = {
|
||||
}
|
||||
},
|
||||
randomGroup(x, y, chance = 1) {
|
||||
if (spawn.spawnChance(chance) && simulation.difficulty > 2 || chance == Infinity) {
|
||||
if (spawn.spawnChance(chance) && simulation.difficulty > 2 || chance === Infinity) {
|
||||
//choose from the possible picklist
|
||||
let pick = spawn.pickList[Math.floor(Math.random() * spawn.pickList.length)];
|
||||
//is the pick able to be a group?
|
||||
@@ -664,23 +664,38 @@ const spawn = {
|
||||
}
|
||||
}
|
||||
},
|
||||
starter(x, y, radius = Math.floor(15 + 20 * Math.random())) { //easy mob for on level 1
|
||||
mobs.spawn(x, y, 8, radius, "#9ccdc6");
|
||||
let me = mob[mob.length - 1];
|
||||
// console.log(`mass=${me.mass}, radius = ${radius}`)
|
||||
me.accelMag = 0.0002
|
||||
me.repulsionRange = 100000 + radius * radius; //squared
|
||||
// me.memory = 120;
|
||||
me.seeAtDistance2 = 2000000 //1400 vision range
|
||||
Matter.Body.setDensity(me, 0.0005) // normal density is 0.001 // this reduces life by half and decreases knockback
|
||||
me.do = function() {
|
||||
this.seePlayerByLookingAt();
|
||||
this.attraction();
|
||||
this.repulsion();
|
||||
this.checkStatus();
|
||||
};
|
||||
},
|
||||
blockGroup(x, y, num = 3 + Math.random() * 8) {
|
||||
for (let i = 0; i < num; i++) {
|
||||
const radius = 25 + Math.floor(Math.random() * 20)
|
||||
spawn.grouper(x + Math.random() * radius, y + Math.random() * radius, radius);
|
||||
spawn.blockGroupMob(x + Math.random() * radius, y + Math.random() * radius, radius);
|
||||
}
|
||||
},
|
||||
grouper(x, y, radius = 25 + Math.floor(Math.random() * 20)) {
|
||||
mobs.spawn(x, y, 4, radius, "#777");
|
||||
blockGroupMob(x, y, radius = 25 + Math.floor(Math.random() * 20)) {
|
||||
mobs.spawn(x, y, 4, radius, "#999");
|
||||
let me = mob[mob.length - 1];
|
||||
me.g = 0.00015; //required if using 'gravity'
|
||||
me.g = 0.00015; //required if using this.gravity
|
||||
me.accelMag = 0.0008 * simulation.accelScale;
|
||||
me.groupingRangeMax = 250000 + Math.random() * 100000;
|
||||
me.groupingRangeMin = (radius * 8) * (radius * 8);
|
||||
me.groupingStrength = 0.0005
|
||||
me.memory = 200;
|
||||
me.isGrouper = true;
|
||||
|
||||
me.do = function() {
|
||||
this.gravity();
|
||||
this.checkStatus();
|
||||
@@ -705,28 +720,159 @@ const spawn = {
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx.strokeStyle = "#000";
|
||||
ctx.strokeStyle = "#0ff";
|
||||
ctx.lineWidth = 1;
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
},
|
||||
starter(x, y, radius = Math.floor(15 + 20 * Math.random())) {
|
||||
//easy mob for on level 1
|
||||
mobs.spawn(x, y, 8, radius, "#9ccdc6");
|
||||
let me = mob[mob.length - 1];
|
||||
// console.log(`mass=${me.mass}, radius = ${radius}`)
|
||||
me.accelMag = 0.0002
|
||||
me.repulsionRange = 100000 + radius * radius; //squared
|
||||
// me.memory = 120;
|
||||
me.seeAtDistance2 = 2000000 //1400 vision range
|
||||
Matter.Body.setDensity(me, 0.0005) // normal density is 0.001 // this reduces life by half and decreases knockback
|
||||
blockBoss(x, y, radius = 30) {
|
||||
const activeBeams = []; // used to draw beams when converting
|
||||
const beamTotalDuration = 60
|
||||
mobs.spawn(x, y, 4, radius, "#999"); //#54291d
|
||||
const me = mob[mob.length - 1];
|
||||
me.isBoss = true;
|
||||
// Matter.Body.setDensity(me, 0.001); //normal density even though its a boss
|
||||
me.damageReduction = 0.06; //extra reduction for a boss, because normal density
|
||||
me.frictionAir = 0.01;
|
||||
me.accelMag = 0.0002;
|
||||
me.onDeath = function() {
|
||||
powerUps.spawnBossPowerUp(this.position.x, this.position.y);
|
||||
for (const who of mob) {
|
||||
if (who.isNecroMob) { //blockMobs leave their body, and die
|
||||
who.leaveBody = true
|
||||
who.damage(Infinity)
|
||||
}
|
||||
}
|
||||
}
|
||||
me.target = player; // the target to lock on. Usually a block, but will be the player under certain conditions
|
||||
me.do = function() {
|
||||
this.seePlayerByLookingAt();
|
||||
this.attraction();
|
||||
this.repulsion();
|
||||
this.checkStatus();
|
||||
};
|
||||
this.seePlayerCheck();
|
||||
if (this.target) { //(this.target === player && this.seePlayer.yes) || this.target !== player
|
||||
const force = Vector.mult(Vector.normalise(Vector.sub(this.target.position, this.position)), this.accelMag * this.mass)
|
||||
this.force.x += force.x;
|
||||
this.force.y += force.y;
|
||||
}
|
||||
|
||||
if (!(simulation.cycle % 30) && !m.isBodiesAsleep) {
|
||||
//find blocks to turn into mobs
|
||||
for (let i = 0; i < body.length; i++) {
|
||||
if (Vector.magnitude(Vector.sub(this.position, body[i].position)) < 700 && !body[i].isNotHoldable) { // check distance for each block
|
||||
Matter.Composite.remove(engine.world, body[i]);
|
||||
this.target = null //player;
|
||||
spawn.blockMob(body[i].position.x, body[i].position.y, body[i], 0);
|
||||
body.splice(i, 1);
|
||||
activeBeams.push([beamTotalDuration, mob[mob.length - 1]]);
|
||||
}
|
||||
}
|
||||
|
||||
// generally, the boss will tend to stay in the player's area but focus on blocks.
|
||||
if (this.distanceToPlayer() > 1500 && this.target === null) {
|
||||
this.target = player; // too far, attract to the player
|
||||
} else {
|
||||
if (body.length) { // look for a new target by finding the closest block
|
||||
let min = Infinity;
|
||||
let closestBlock = null;
|
||||
for (const block of body) {
|
||||
const dist = Vector.magnitudeSquared(Vector.sub(this.position, block.position))
|
||||
if (dist < min && Matter.Query.ray(map, this.position, block.position).length === 0) {
|
||||
min = dist;
|
||||
closestBlock = block;
|
||||
}
|
||||
}
|
||||
this.target = closestBlock;
|
||||
}
|
||||
}
|
||||
|
||||
//randomly spawn new mobs from nothing
|
||||
if (!(simulation.cycle % 120)) {
|
||||
let count = 0
|
||||
for (let i = 0, len = mob.length; i < len; i++) {
|
||||
if (mob[i].isNecroMob) count++
|
||||
}
|
||||
if (count < 12 * Math.random() * Math.random()) { //limit number of spawns if there are already too many blockMobs
|
||||
const unit = Vector.normalise(Vector.sub(player.position, this.position))
|
||||
for (let i = 0, len = 3 * Math.random(); i < len; i++) {
|
||||
const where = Vector.add(Vector.mult(unit, radius + 200 * Math.random()), this.position)
|
||||
spawn.blockMob(where.x + 100 * (Math.random() - 0.5), where.y + 100 * (Math.random() - 0.5), null);
|
||||
this.torque += 0.000035 * this.inertia; //spin after spawning
|
||||
activeBeams.push([beamTotalDuration, mob[mob.length - 1]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
for (let i = 0; i < activeBeams.length; i++) { // draw beams on new mobs
|
||||
const [duration, newBlockMob] = activeBeams[i];
|
||||
if (duration === 0) {
|
||||
activeBeams.splice(i, 1);
|
||||
continue;
|
||||
}
|
||||
if (newBlockMob.alive) {
|
||||
const vertexIndex = Math.floor((newBlockMob.vertices.length - 1) * duration / beamTotalDuration)
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(this.position.x, this.position.y);
|
||||
ctx.lineTo(newBlockMob.vertices[vertexIndex].x, newBlockMob.vertices[vertexIndex].y);
|
||||
|
||||
//outline mob
|
||||
ctx.moveTo(newBlockMob.vertices[0].x, newBlockMob.vertices[0].y);
|
||||
for (let j = 1; j < newBlockMob.vertices.length; j++) {
|
||||
ctx.lineTo(newBlockMob.vertices[j].x, newBlockMob.vertices[j].y);
|
||||
}
|
||||
ctx.lineTo(newBlockMob.vertices[0].x, newBlockMob.vertices[0].y);
|
||||
|
||||
ctx.strokeStyle = "#0ff";
|
||||
ctx.lineWidth = 3;
|
||||
ctx.stroke();
|
||||
}
|
||||
activeBeams[i][0]--; // shorten duration
|
||||
}
|
||||
}
|
||||
},
|
||||
blockMob(x, y, host, growCycles = 60) {
|
||||
if (host === null) {
|
||||
mobs.spawn(x, y, 4, 1.25 + 3.5 * Math.random(), "#999");
|
||||
} else {
|
||||
const sideLength = Vector.magnitude(Vector.sub(host.vertices[0], host.vertices[1])) + Vector.magnitude(Vector.sub(host.vertices[1], host.vertices[2])) / 2 //average of first 2 sides
|
||||
mobs.spawn(x, y, 4, Math.min(70, sideLength), "#999");
|
||||
if (host.bounds.max.x - host.bounds.min.x < 150 && host.bounds.max.y - host.bounds.min.y < 150) {
|
||||
Matter.Body.setVertices(mob[mob.length - 1], host.vertices) //if not too big match vertices of host exactly
|
||||
// mob[mob.length - 1].radius =
|
||||
}
|
||||
}
|
||||
const me = mob[mob.length - 1];
|
||||
me.damageReduction = 0.5; //only until done growing
|
||||
me.isNecroMob = true
|
||||
me.g = 0.00012; //required if using this.gravity
|
||||
me.accelMag = 0.0003 * Math.sqrt(simulation.accelScale);
|
||||
me.memory = 120;
|
||||
me.leaveBody = false;
|
||||
me.isDropPowerUp = false;
|
||||
// me.showHealthBar = false;
|
||||
me.cycle = 0
|
||||
me.do = function() { //grow phase only occurs for growCycles
|
||||
this.checkStatus();
|
||||
this.seePlayerCheck();
|
||||
|
||||
if (!m.isBodiesAsleep) {
|
||||
this.cycle++
|
||||
if (this.cycle > growCycles) {
|
||||
this.damageReduction = 1.8 //take extra damage
|
||||
this.do = this.normalDo
|
||||
} else {
|
||||
const scale = 1.04; //if 120 use 1.02
|
||||
Matter.Body.scale(this, scale, scale);
|
||||
this.radius *= scale;
|
||||
}
|
||||
}
|
||||
}
|
||||
me.normalDo = function() {
|
||||
this.gravity();
|
||||
this.checkStatus();
|
||||
this.seePlayerCheck();
|
||||
this.attraction();
|
||||
}
|
||||
},
|
||||
cellBossCulture(x, y, radius = 20, num = 5) {
|
||||
const cellID = Math.random()
|
||||
@@ -1043,7 +1189,7 @@ const spawn = {
|
||||
// me.friction = 0.1;
|
||||
// me.frictionAir = 0;
|
||||
// me.accelMag = 0.001 * Math.sqrt(simulation.accelScale);
|
||||
// me.g = me.accelMag * 0.6; //required if using 'gravity'
|
||||
// me.g = me.accelMag * 0.6; //required if using this.gravity
|
||||
// me.memory = 180;
|
||||
// spawn.shield(me, x, y);
|
||||
// me.do = function() {
|
||||
@@ -1076,8 +1222,8 @@ const spawn = {
|
||||
me.friction = 0;
|
||||
me.frictionAir = 0.006;
|
||||
me.lookTorque = 0.0000008; //controls spin while looking for player
|
||||
me.g = 0.0002; //required if using 'gravity'
|
||||
me.seePlayerFreq = Math.round((40 + 25 * Math.random()) * simulation.lookFreqScale);
|
||||
me.g = 0.0002; //required if using this.gravity
|
||||
me.seePlayerFreq = Math.floor((40 + 25 * Math.random()));
|
||||
const springStiffness = 0.00014;
|
||||
const springDampening = 0.0005;
|
||||
|
||||
@@ -1127,7 +1273,7 @@ const spawn = {
|
||||
mobs.spawn(x, y, 5, radius, "rgb(0,200,180)");
|
||||
let me = mob[mob.length - 1];
|
||||
me.accelMag = 0.04;
|
||||
me.g = 0.0017; //required if using 'gravity'
|
||||
me.g = 0.0017; //required if using this.gravity
|
||||
me.frictionAir = 0.01;
|
||||
me.friction = 1
|
||||
me.frictionStatic = 1
|
||||
@@ -1167,7 +1313,7 @@ const spawn = {
|
||||
let me = mob[mob.length - 1];
|
||||
me.isBoss = true;
|
||||
|
||||
me.g = 0.005; //required if using 'gravity'
|
||||
me.g = 0.005; //required if using this.gravity
|
||||
me.frictionAir = 0.01;
|
||||
me.friction = 1
|
||||
me.frictionStatic = 1
|
||||
@@ -1505,8 +1651,8 @@ const spawn = {
|
||||
me.friction = 0;
|
||||
me.frictionAir = 0.0067;
|
||||
me.lookTorque = 0.0000008; //controls spin while looking for player
|
||||
me.g = 0.0002; //required if using 'gravity'
|
||||
me.seePlayerFreq = Math.round((30 + 20 * Math.random()) * simulation.lookFreqScale);
|
||||
me.g = 0.0002; //required if using this.gravity
|
||||
me.seePlayerFreq = Math.floor((30 + 20 * Math.random()));
|
||||
const springStiffness = 0.00014;
|
||||
const springDampening = 0.0005;
|
||||
|
||||
@@ -1865,7 +2011,7 @@ const spawn = {
|
||||
me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front
|
||||
Matter.Body.rotate(me, Math.random() * Math.PI * 2);
|
||||
me.accelMag = 0.00018 * Math.sqrt(simulation.accelScale);
|
||||
me.seePlayerFreq = Math.floor(30 * simulation.lookFreqScale);
|
||||
me.seePlayerFreq = 30
|
||||
me.memory = 420;
|
||||
me.restitution = 1;
|
||||
me.frictionAir = 0.01;
|
||||
@@ -2006,7 +2152,7 @@ const spawn = {
|
||||
me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front
|
||||
Matter.Body.rotate(me, Math.random() * Math.PI * 2);
|
||||
me.accelMag = 0.00055 * Math.sqrt(simulation.accelScale);
|
||||
me.seePlayerFreq = Math.floor(30 * simulation.lookFreqScale);
|
||||
me.seePlayerFreq = 30;
|
||||
me.memory = 420;
|
||||
me.restitution = 1;
|
||||
me.frictionAir = 0.05;
|
||||
@@ -2634,7 +2780,7 @@ const spawn = {
|
||||
let me = mob[mob.length - 1];
|
||||
me.isVerticesChange = true
|
||||
me.accelMag = 0.0006 * simulation.accelScale;
|
||||
// me.g = 0.0002; //required if using 'gravity'
|
||||
// me.g = 0.0002; //required if using this.gravity
|
||||
me.delay = 360 * simulation.CDScale;
|
||||
me.spikeVertex = 0;
|
||||
me.spikeLength = 0;
|
||||
@@ -2712,7 +2858,7 @@ const spawn = {
|
||||
mobs.spawn(x, y, 5, radius, "rgb(221,102,119)");
|
||||
let me = mob[mob.length - 1];
|
||||
me.accelMag = 0.00034 * simulation.accelScale;
|
||||
me.g = 0.00015; //required if using 'gravity'
|
||||
me.g = 0.00015; //required if using this.gravity
|
||||
me.frictionStatic = 0;
|
||||
me.friction = 0;
|
||||
me.delay = 90 * simulation.CDScale;
|
||||
@@ -2768,7 +2914,7 @@ const spawn = {
|
||||
Matter.Body.setDensity(me, 0.002); //extra dense //normal is 0.001 //makes effective life much larger
|
||||
me.accelMag = 0.001 * Math.sqrt(simulation.accelScale);
|
||||
me.frictionAir = 0.01;
|
||||
me.g = 0.0002; //required if using 'gravity'
|
||||
me.g = 0.0002; //required if using this.gravity
|
||||
me.stroke = "transparent"; //used for drawSneaker
|
||||
me.alpha = 1; //used in drawSneaker
|
||||
// me.leaveBody = false;
|
||||
@@ -2882,7 +3028,7 @@ const spawn = {
|
||||
// me.blinkLength = 150 + Math.round(Math.random() * 200); //required for blink
|
||||
// me.isStatic = true;
|
||||
// me.memory = 360;
|
||||
// me.seePlayerFreq = Math.round((40 + 30 * Math.random()) * simulation.lookFreqScale);
|
||||
// me.seePlayerFreq = Math.round((40 + 30 * Math.random()));
|
||||
// // me.isBig = false;
|
||||
// // me.scaleMag = Math.max(5 - me.mass, 1.75);
|
||||
// me.onDeath = function () {
|
||||
@@ -2931,7 +3077,7 @@ const spawn = {
|
||||
me.hoverElevation = 460 + (Math.random() - 0.5) * 200; //squared
|
||||
me.hoverXOff = (Math.random() - 0.5) * 100;
|
||||
me.accelMag = Math.floor(10 * (Math.random() + 4.5)) * 0.00001 * simulation.accelScale;
|
||||
me.g = 0.0002; //required if using 'gravity' // gravity called in hoverOverPlayer
|
||||
me.g = 0.0002; //required if using this.gravity // gravity called in hoverOverPlayer
|
||||
me.frictionStatic = 0;
|
||||
me.friction = 0;
|
||||
me.frictionAir = 0.01;
|
||||
@@ -3062,7 +3208,7 @@ const spawn = {
|
||||
};
|
||||
Matter.Body.setDensity(me, 0.00004); //normal is 0.001
|
||||
me.timeLeft = 200;
|
||||
me.g = 0.001; //required if using 'gravity'
|
||||
me.g = 0.001; //required if using this.gravity
|
||||
me.frictionAir = 0;
|
||||
me.restitution = 0.8;
|
||||
me.leaveBody = false;
|
||||
@@ -3114,7 +3260,7 @@ const spawn = {
|
||||
}
|
||||
Matter.Body.setDensity(me, 0.00005); //normal is 0.001
|
||||
me.timeLeft = 140 + Math.floor(Math.random() * 30);
|
||||
me.g = 0.001; //required if using 'gravity'
|
||||
me.g = 0.001; //required if using this.gravity
|
||||
me.frictionAir = 0;
|
||||
me.restitution = 1;
|
||||
me.leaveBody = false;
|
||||
@@ -3254,7 +3400,7 @@ const spawn = {
|
||||
};
|
||||
Matter.Body.setDensity(me, 0.00005); //normal is 0.001
|
||||
me.timeLeft = 120;
|
||||
// me.g = 0.0005; //required if using 'gravity'
|
||||
// me.g = 0.0005; //required if using this.gravity
|
||||
me.frictionAir = 0;
|
||||
me.restitution = 0;
|
||||
me.leaveBody = false;
|
||||
@@ -3486,7 +3632,7 @@ const spawn = {
|
||||
|
||||
me.lifeSpan = lifeSpan;
|
||||
me.timeLeft = me.lifeSpan;
|
||||
// me.g = 0.0002; //required if using 'gravity'
|
||||
// me.g = 0.0002; //required if using this.gravity
|
||||
me.frictionAir = 0;
|
||||
me.restitution = 0.8;
|
||||
me.leaveBody = false;
|
||||
@@ -3701,7 +3847,7 @@ const spawn = {
|
||||
spawner(x, y, radius = 55 + Math.ceil(Math.random() * 50)) {
|
||||
mobs.spawn(x, y, 4, radius, "rgb(255,150,0)");
|
||||
let me = mob[mob.length - 1];
|
||||
me.g = 0.0004; //required if using 'gravity'
|
||||
me.g = 0.0004; //required if using this.gravity
|
||||
me.leaveBody = false;
|
||||
// me.isDropPowerUp = false;
|
||||
me.onDeath = function() { //run this function on death
|
||||
@@ -3731,12 +3877,12 @@ const spawn = {
|
||||
me.collisionFilter.mask = cat.player | cat.bullet | cat.body | cat.map | cat.mob
|
||||
me.showHealthBar = false;
|
||||
Matter.Body.setDensity(me, 0.0001); //normal is 0.001
|
||||
me.g = 0.00002; //required if using 'gravity'
|
||||
me.g = 0.00002; //required if using this.gravity
|
||||
me.accelMag = 0.00012 * simulation.accelScale;
|
||||
// me.memory = 30;
|
||||
me.isDropPowerUp = false
|
||||
me.leaveBody = false;
|
||||
me.seePlayerFreq = Math.round((80 + 50 * Math.random()) * simulation.lookFreqScale);
|
||||
me.seePlayerFreq = Math.floor((80 + 50 * Math.random()));
|
||||
me.frictionAir = 0.004;
|
||||
me.do = function() {
|
||||
this.gravity();
|
||||
@@ -3755,7 +3901,7 @@ const spawn = {
|
||||
// me.onHit = function() { //run this function on hitting player
|
||||
// this.explode();
|
||||
// };
|
||||
// me.g = 0.0003; //required if using 'gravity'
|
||||
// me.g = 0.0003; //required if using this.gravity
|
||||
// me.seePlayerFreq = 50 + Math.floor(Math.random() * 20)
|
||||
// me.do = function() {
|
||||
// this.gravity();
|
||||
@@ -3799,7 +3945,7 @@ const spawn = {
|
||||
//run this function on hitting player
|
||||
this.explode();
|
||||
};
|
||||
me.g = 0.0004; //required if using 'gravity'
|
||||
me.g = 0.0004; //required if using this.gravity
|
||||
me.do = function() {
|
||||
this.gravity();
|
||||
this.seePlayerCheck();
|
||||
@@ -3807,7 +3953,7 @@ const spawn = {
|
||||
this.attraction();
|
||||
};
|
||||
},
|
||||
snakeSpitBoss(x, y, radius = 50) { //snake boss with a laser head
|
||||
snakeSpitBoss(x, y, radius = 50) {
|
||||
const nodes = Math.min(8 + Math.ceil(0.5 * simulation.difficulty), 40)
|
||||
let angle = Math.PI
|
||||
let mag = 300
|
||||
@@ -3834,14 +3980,14 @@ const spawn = {
|
||||
me.closestVertex1 = 0;
|
||||
// me.closestVertex2 = 1;
|
||||
me.cycle = 0
|
||||
me.damageReduction = 0.25
|
||||
me.damageReduction = 0.2
|
||||
me.do = function() {
|
||||
// this.armor();
|
||||
this.seePlayerByHistory()
|
||||
this.checkStatus();
|
||||
this.attraction();
|
||||
this.cycle++
|
||||
if (this.seePlayer.recall && ((this.cycle % 15) === 0) && !m.isBodiesAsleep) {
|
||||
if (this.seePlayer.recall && ((this.cycle % 10) === 0) && !m.isBodiesAsleep) {
|
||||
if (this.canFire) {
|
||||
if (this.cycle > 120) {
|
||||
this.cycle = 0
|
||||
@@ -4032,7 +4178,7 @@ const spawn = {
|
||||
let me = mob[mob.length - 1];
|
||||
me.isBoss = true;
|
||||
|
||||
me.g = 0.0001; //required if using 'gravity'
|
||||
me.g = 0.0001; //required if using this.gravity
|
||||
me.accelMag = 0.002 * simulation.accelScale;
|
||||
me.memory = 20;
|
||||
Matter.Body.setDensity(me, 0.0005 + 0.0002 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
|
||||
|
||||
16
js/tech.js
16
js/tech.js
@@ -306,9 +306,9 @@
|
||||
frequency: 2,
|
||||
frequencyDefault: 2,
|
||||
allowed() {
|
||||
return b.inventory.length > 0
|
||||
return b.inventory.length > 2
|
||||
},
|
||||
requires: "at least 1 gun",
|
||||
requires: "at least 3 guns",
|
||||
effect() {
|
||||
tech.isDamageForGuns = true;
|
||||
},
|
||||
@@ -324,9 +324,9 @@
|
||||
frequency: 2,
|
||||
frequencyDefault: 2,
|
||||
allowed() {
|
||||
return b.inventory.length > 0
|
||||
return b.inventory.length > 1
|
||||
},
|
||||
requires: "at least 1 gun",
|
||||
requires: "at least 2 guns",
|
||||
effect() {
|
||||
tech.isFireRateForGuns = true;
|
||||
b.setFireCD();
|
||||
@@ -2405,7 +2405,7 @@
|
||||
},
|
||||
{
|
||||
name: "energy conservation",
|
||||
description: "<strong>6%</strong> of <strong class='color-d'>damage</strong> done recovered as <strong class='color-f'>energy</strong>",
|
||||
description: "<strong>5%</strong> of <strong class='color-d'>damage</strong> done recovered as <strong class='color-f'>energy</strong>",
|
||||
maxCount: 9,
|
||||
count: 0,
|
||||
frequency: 1,
|
||||
@@ -2415,7 +2415,7 @@
|
||||
},
|
||||
requires: "",
|
||||
effect() {
|
||||
tech.energySiphon += 0.06;
|
||||
tech.energySiphon += 0.05;
|
||||
},
|
||||
remove() {
|
||||
tech.energySiphon = 0;
|
||||
@@ -5053,7 +5053,7 @@
|
||||
},
|
||||
remove() {
|
||||
tech.laserFieldDrain = 0.002;
|
||||
tech.laserDamage = 0.16; //used in check on pulse: tech.laserDamage === 0.15
|
||||
tech.laserDamage = 0.16; //used in check on pulse: tech.laserDamage === 0.16
|
||||
tech.laserColor = "#f00"
|
||||
tech.laserColorAlpha = "rgba(255, 0, 0, 0.5)"
|
||||
}
|
||||
@@ -5219,7 +5219,7 @@
|
||||
frequency: 2,
|
||||
frequencyDefault: 2,
|
||||
allowed() {
|
||||
return tech.haveGunCheck("laser") && tech.laserReflections < 3 && !tech.isWideLaser && tech.laserDamage === 0.15
|
||||
return tech.haveGunCheck("laser") && tech.laserReflections < 3 && !tech.isWideLaser && tech.laserDamage === 0.16
|
||||
},
|
||||
requires: "laser gun, not specular reflection, diffuse, free-electron laser",
|
||||
effect() {
|
||||
|
||||
Reference in New Issue
Block a user