animated level load
animated new level load graphics for reactor and final level autoZoom code rewritten to work with pause better using the ephemera system this might cause bugs, I already found a few intro level renamed initial extra ammo power ups on why difficulty for final and reactor levels removed falling off the map damage on levels that still had falling off damage mob: stinger - has speed that adjusts as it flaps it's wings and a short range laser tech: strange loop - +9% damage, removing it gives null hypothesis and strange attractor tech: martingale - +11% damage, removing this has a 50% chance to not remove and to double it's damage paradigm shift removes 6 health when it ejects a tech, but now has a 85->97% chance to work ammo, heal, research tech spawn extra power ups after each time you take them tungsten carbide skin has a hexagon look and +222->300 max health Bayesian statistics spawn 3->6 research ansatz spawns 2->3 research if you have no research Ψ(t) collapse 16->21 research futures exchange 4.3->4.7% duplication replication 9->10 duplication stimulated emission 17->19% duplication anthropic principle spawn 5->16 heals when you die supply chain: no long gives JUNK instead triples the frequency of finding applied science electronegativity 0.22->0.26% damage per energy non-renewables 88->97% damage anticorrelation 100->111% damage decorrelation 70->77% defense parasitism 83->93% damage torpor 66->74% defense bug fix: recycling works with mass-energy (although it doesn't do much) ternary wasn't working in many situations, but it should now fixed bubble fusion exploit that triggers on mobs in factory endlessly bot fabrication was making 1 extra bot and giving negative research sometimes
This commit is contained in:
201
js/spawn.js
201
js/spawn.js
@@ -22,9 +22,10 @@ const spawn = {
|
||||
fullPickList: [
|
||||
"slasher", "slasher", "slasher2", "slasher3",
|
||||
"hopper", "hopper", "hopMother", "hopMother",
|
||||
"flutter", "flutter", "flutter",
|
||||
"stabber", "stabber", "stabber",
|
||||
"springer", "springer", "springer",
|
||||
"stinger", "stinger", "stinger",
|
||||
"flutter", "flutter",
|
||||
"shooter", "shooter",
|
||||
"grenadier", "grenadier",
|
||||
"striker", "striker",
|
||||
@@ -34,7 +35,7 @@ const spawn = {
|
||||
],
|
||||
mobTypeSpawnOrder: [], //preset list of mob names calculated at the start of a run by the randomSeed
|
||||
mobTypeSpawnIndex: 0, //increases as the mob type cycles
|
||||
allowedGroupList: ["spinner", "striker", "springer", "laser", "focuser", "beamer", "exploder", "spawner", "shooter", "launcher", "launcherOne", "stabber", "sniper", "pulsar", "grenadier", "slasher", "flutter"],
|
||||
allowedGroupList: ["spinner", "striker", "springer", "laser", "focuser", "beamer", "exploder", "spawner", "shooter", "launcher", "launcherOne", "stabber", "sniper", "pulsar", "grenadier", "slasher", "flutter", "stinger"],
|
||||
setSpawnList() { //this is run at the start of each new level to determine the possible mobs for the level
|
||||
spawn.pickList.splice(0, 1);
|
||||
const push = spawn.mobTypeSpawnOrder[spawn.mobTypeSpawnIndex++ % spawn.mobTypeSpawnOrder.length]
|
||||
@@ -3837,6 +3838,202 @@ const spawn = {
|
||||
// }
|
||||
};
|
||||
},
|
||||
stinger(x, y, radius = 18 + 4 * Math.random()) {
|
||||
const color = '#5bc'
|
||||
mobs.spawn(x, y, 7, radius, color);
|
||||
let me = mob[mob.length - 1];
|
||||
Matter.Body.setDensity(me, 0.0025); //extra dense //normal is 0.001 //makes effective life much larger
|
||||
// me.damageReduction = 0.04 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
|
||||
|
||||
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.0015 + 0.0007 * Math.sqrt(simulation.accelScale);
|
||||
me.frictionAir = 0.04;
|
||||
// me.seePlayerFreq = 40 + Math.floor(13 * Math.random())
|
||||
me.memory = 240;
|
||||
me.restitution = 0.8;
|
||||
me.frictionStatic = 0;
|
||||
me.friction = 0;
|
||||
me.lookTorque = 0.000001 * (Math.random() > 0.5 ? -1 : 1);
|
||||
me.fireDir = { x: 0, y: 0 }
|
||||
spawn.shield(me, x, y);
|
||||
|
||||
// me.onDeath = function() {};
|
||||
me.flapRate = 0.06 + 0.03 * Math.random()
|
||||
me.flapRadius = 40 + radius * 3
|
||||
me.do = function () {
|
||||
this.seePlayerByHistory()
|
||||
this.checkStatus();
|
||||
if (this.seePlayer.recall) {
|
||||
this.force.x += Math.cos(this.angle) * this.accelMag * this.mass
|
||||
this.force.y += Math.sin(this.angle) * this.accelMag * this.mass
|
||||
|
||||
//set direction to turn to fire
|
||||
if (!(simulation.cycle % this.seePlayerFreq)) {
|
||||
this.fireDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position));
|
||||
//dot product can't tell if mob is facing directly away or directly towards, so check if pointed directly away from player every few cycles
|
||||
const mod = (a, n) => a - Math.floor(a / n) * n
|
||||
const sub = Vector.sub(m.pos, this.position) //check by comparing different between angles. Give this a nudge if angles are 180 degree different
|
||||
const diff = mod(Math.atan2(sub.y, sub.x) - this.angle + Math.PI, 2 * Math.PI) - Math.PI
|
||||
if (Math.abs(diff) > 2.8) this.torque += 0.0002 * this.inertia * Math.random();
|
||||
}
|
||||
|
||||
//rotate towards fireDir
|
||||
const angle = this.angle + Math.PI / 2;
|
||||
c = Math.cos(angle) * this.fireDir.x + Math.sin(angle) * this.fireDir.y;
|
||||
const threshold = 0.4;
|
||||
const turn = 0.00002 * this.inertia
|
||||
if (c > threshold) {
|
||||
this.torque += turn;
|
||||
} else if (c < -threshold) {
|
||||
this.torque -= turn;
|
||||
}
|
||||
|
||||
// this.accelMag = 0.0006 + 0.0007 * Math.sqrt(simulation.accelScale);
|
||||
this.frictionAir = 0.11 + 0.09 * Math.sin(simulation.cycle * this.flapRate - Math.PI / 2)
|
||||
|
||||
const flapArc = 0.8 //don't go past 1.57 for normal flaps
|
||||
ctx.fillStyle = `hsla(${160 + 40 * Math.random()}, 100%, ${25 + 25 * Math.random() * Math.random()}%, 0.2)`; //"rgba(0,235,255,0.3)"; // ctx.fillStyle = `hsla(44, 79%, 31%,0.4)`; //"rgba(0,235,255,0.3)";
|
||||
this.wing(this.angle + 2.1 + flapArc * Math.sin(simulation.cycle * this.flapRate), this.flapRadius)
|
||||
this.wing(this.angle - 2.1 - flapArc * Math.sin(simulation.cycle * this.flapRate), this.flapRadius)
|
||||
|
||||
const seeRange = 550 + 35 * simulation.difficultyMode;
|
||||
if (this.distanceToPlayer() < seeRange) {
|
||||
const vertexCollision = function (v1, v1End, domain) {
|
||||
for (let i = 0; i < domain.length; ++i) {
|
||||
let vertices = domain[i].vertices;
|
||||
const len = vertices.length - 1;
|
||||
for (let j = 0; j < len; j++) {
|
||||
results = simulation.checkLineIntersection(v1, v1End, vertices[j], vertices[j + 1]);
|
||||
if (results.onLine1 && results.onLine2) {
|
||||
const dx = v1.x - results.x;
|
||||
const dy = v1.y - results.y;
|
||||
const dist2 = dx * dx + dy * dy;
|
||||
if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) {
|
||||
best = {
|
||||
x: results.x,
|
||||
y: results.y,
|
||||
dist2: dist2,
|
||||
who: domain[i],
|
||||
v1: vertices[j],
|
||||
v2: vertices[j + 1]
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
results = simulation.checkLineIntersection(v1, v1End, vertices[0], vertices[len]);
|
||||
if (results.onLine1 && results.onLine2) {
|
||||
const dx = v1.x - results.x;
|
||||
const dy = v1.y - results.y;
|
||||
const dist2 = dx * dx + dy * dy;
|
||||
if (dist2 < best.dist2) {
|
||||
best = {
|
||||
x: results.x,
|
||||
y: results.y,
|
||||
dist2: dist2,
|
||||
who: domain[i],
|
||||
v1: vertices[0],
|
||||
v2: vertices[len]
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
best = {
|
||||
x: null,
|
||||
y: null,
|
||||
dist2: Infinity,
|
||||
who: null,
|
||||
v1: null,
|
||||
v2: null
|
||||
};
|
||||
const seeRangeRandom = seeRange - 200 - 150 * Math.random()
|
||||
const look = {
|
||||
x: this.position.x + seeRangeRandom * Math.cos(this.angle),
|
||||
y: this.position.y + seeRangeRandom * Math.sin(this.angle)
|
||||
};
|
||||
vertexCollision(this.position, look, map);
|
||||
vertexCollision(this.position, look, body);
|
||||
if (!m.isCloak) vertexCollision(this.position, look, [playerBody, playerHead]);
|
||||
|
||||
// hitting player
|
||||
if ((best.who === playerBody || best.who === playerHead) && m.immuneCycle < m.cycle) {
|
||||
const dmg = 0.002 * simulation.dmgScale;
|
||||
m.damage(dmg);
|
||||
//draw damage
|
||||
ctx.fillStyle = color;
|
||||
ctx.beginPath();
|
||||
ctx.arc(best.x, best.y, 5 + dmg * 1500, 0, 2 * Math.PI);
|
||||
ctx.fill();
|
||||
}
|
||||
//draw beam
|
||||
const vertex = 3
|
||||
if (best.dist2 === Infinity) best = look;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(this.vertices[vertex].x, this.vertices[vertex].y);
|
||||
ctx.lineTo(best.x, best.y);
|
||||
ctx.strokeStyle = color;
|
||||
ctx.lineWidth = 2;
|
||||
ctx.setLineDash([50 + 120 * Math.random(), 50 * Math.random()]);
|
||||
ctx.stroke();
|
||||
ctx.setLineDash([]);
|
||||
|
||||
// ctx.beginPath();
|
||||
// ctx.arc(this.vertices[vertex].x, this.vertices[vertex].y, 5, 0, 2 * Math.PI); //* this.fireCycle / this.fireDelay
|
||||
// ctx.fillStyle = color;
|
||||
// ctx.fill();
|
||||
}
|
||||
// else {
|
||||
// ctx.beginPath();
|
||||
// ctx.arc(this.vertices[1].x, this.vertices[1].y, 1 + 0.3 * (simulation.cycle % this.laserInterval), 0, 2 * Math.PI); //* this.fireCycle / this.fireDelay
|
||||
// ctx.fillStyle = color;
|
||||
// ctx.fill();
|
||||
// }
|
||||
}
|
||||
// else { //flocking behavior (not working yet)
|
||||
// this.force.x += Math.cos(this.angle) * this.accelMag * this.mass
|
||||
// this.force.y += Math.sin(this.angle) * this.accelMag * this.mass
|
||||
// //set direction to turn to fire
|
||||
// if (!(simulation.cycle % this.seePlayerFreq)) {
|
||||
// //find nearest mob and maintain a distance
|
||||
// let nearestMob = null
|
||||
// let nearestMobDistance = Infinity
|
||||
// for (let i = 0; i < mob.length; i++) {
|
||||
// const newMobDistance = Vector.magnitude(Vector.sub(this.position, mob[i].position))
|
||||
// if (mob[i].isDropPowerUp && mob[i].alive && newMobDistance < nearestMobDistance) { //&& !mob[i].isBoss
|
||||
// nearestMobDistance = newMobDistance
|
||||
// nearestMob = mob[i]
|
||||
// }
|
||||
// }
|
||||
// if (nearestMob) {
|
||||
// // console.log(nearestMob)
|
||||
// this.fireDir = Vector.normalise(Vector.sub(nearestMob.position, this.position));
|
||||
// //dot product can't tell if mob is facing directly away or directly towards, so check if pointed directly away from player every few cycles
|
||||
// const mod = (a, n) => {
|
||||
// return a - Math.floor(a / n) * n
|
||||
// }
|
||||
// const sub = Vector.sub(nearestMob.position, this.position) //check by comparing different between angles. Give this a nudge if angles are 180 degree different
|
||||
// const diff = mod(Math.atan2(sub.y, sub.x) - this.angle + Math.PI, 2 * Math.PI) - Math.PI
|
||||
// if (Math.abs(diff) > 2.8) this.torque += 0.0002 * this.inertia * Math.random();
|
||||
// }
|
||||
// }
|
||||
// //rotate towards fireDir
|
||||
// const angle = this.angle + Math.PI / 2;
|
||||
// c = Math.cos(angle) * this.fireDir.x + Math.sin(angle) * this.fireDir.y;
|
||||
// const threshold = 0.4;
|
||||
// const turn = 0.000025 * this.inertia
|
||||
// if (c > threshold) {
|
||||
// this.torque += turn;
|
||||
// } else if (c < -threshold) {
|
||||
// this.torque -= turn;
|
||||
// }
|
||||
// const flapArc = 0.7 //don't go past 1.57 for normal flaps
|
||||
// ctx.fillStyle = `hsla(${160 + 40 * Math.random()}, 100%, ${25 + 25 * Math.random() * Math.random()}%, 0.2)`; //"rgba(0,235,255,0.3)"; // ctx.fillStyle = `hsla(44, 79%, 31%,0.4)`; //"rgba(0,235,255,0.3)";
|
||||
// this.wing(this.angle + Math.PI / 2 + flapArc * Math.sin(simulation.cycle * this.flapRate), this.flapRadius)
|
||||
// this.wing(this.angle - Math.PI / 2 - flapArc * Math.sin(simulation.cycle * this.flapRate), this.flapRadius)
|
||||
// }
|
||||
};
|
||||
},
|
||||
beetleBoss(x, y, radius = 50) {
|
||||
mobs.spawn(x, y, 7, radius, '#16576b');
|
||||
let me = mob[mob.length - 1];
|
||||
|
||||
Reference in New Issue
Block a user