slasher mob variants
new community training level diamagnetism by Richard0820 it's at the end of the training levels start training by click the top right button at the load screen slasher mob variant with 2 laser swords slasher mob variant with a laser spear suckerBoss pulls in powerUps and makes them orbit better shooterBoss fires faster and larger bullets wormhole 4 -> 5% duplication, and a 10% reduction in energy cost drones fire faster and aim more accurately quenching gives 10% more max health and harm snake tail mobs have 15% less health tungsten carbide properly gives 222 health in addition to the bonus max health
This commit is contained in:
48
js/bullet.js
48
js/bullet.js
@@ -2832,19 +2832,13 @@ const b = {
|
||||
}
|
||||
if (tech.isLaserPush) { //push mobs away
|
||||
const index = path.length - 1
|
||||
Matter.Body.setVelocity(best.who, {
|
||||
x: best.who.velocity.x * 0.97,
|
||||
y: best.who.velocity.y * 0.97
|
||||
});
|
||||
Matter.Body.setVelocity(best.who, { x: best.who.velocity.x * 0.97, y: best.who.velocity.y * 0.97 });
|
||||
const force = Vector.mult(Vector.normalise(Vector.sub(path[index], path[Math.max(0, index - 1)])), 0.003 * push * Math.min(6, best.who.mass))
|
||||
Matter.Body.applyForce(best.who, path[index], force)
|
||||
}
|
||||
} else if (tech.isLaserPush && best.who.classType === "body") {
|
||||
const index = path.length - 1
|
||||
Matter.Body.setVelocity(best.who, {
|
||||
x: best.who.velocity.x * 0.97,
|
||||
y: best.who.velocity.y * 0.97
|
||||
});
|
||||
Matter.Body.setVelocity(best.who, { x: best.who.velocity.x * 0.97, y: best.who.velocity.y * 0.97 });
|
||||
const force = Vector.mult(Vector.normalise(Vector.sub(path[index], path[Math.max(0, index - 1)])), 0.003 * push * Math.min(6, best.who.mass))
|
||||
Matter.Body.applyForce(best.who, path[index], force)
|
||||
}
|
||||
@@ -3679,7 +3673,7 @@ const b = {
|
||||
}, speed = 1) {
|
||||
const me = bullet.length;
|
||||
const THRUST = 0.0015
|
||||
const dir = m.angle + 0.4 * (Math.random() - 0.5);
|
||||
const dir = m.angle + 0.2 * (Math.random() - 0.5);
|
||||
const RADIUS = (4.5 + 3 * Math.random())
|
||||
bullet[me] = Bodies.polygon(where.x, where.y, 8, RADIUS, {
|
||||
angle: dir,
|
||||
@@ -3822,7 +3816,7 @@ const b = {
|
||||
!mob[i].isInvulnerable
|
||||
) {
|
||||
const TARGET_VECTOR = Vector.sub(this.position, mob[i].position)
|
||||
const DIST = Vector.magnitude(TARGET_VECTOR);
|
||||
const DIST = Vector.magnitude(TARGET_VECTOR)
|
||||
if (DIST < closeDist) {
|
||||
closeDist = DIST;
|
||||
this.lockedOn = mob[i]
|
||||
@@ -3931,18 +3925,12 @@ const b = {
|
||||
}
|
||||
// speed cap instead of friction to give more agility
|
||||
if (this.speed > 6) {
|
||||
Matter.Body.setVelocity(this, {
|
||||
x: this.velocity.x * 0.97,
|
||||
y: this.velocity.y * 0.97
|
||||
});
|
||||
Matter.Body.setVelocity(this, { x: this.velocity.x * 0.97, y: this.velocity.y * 0.97 });
|
||||
}
|
||||
}
|
||||
})
|
||||
Composite.add(engine.world, bullet[me]); //add bullet to world
|
||||
Matter.Body.setVelocity(bullet[me], {
|
||||
x: speed * Math.cos(dir),
|
||||
y: speed * Math.sin(dir)
|
||||
});
|
||||
Matter.Body.setVelocity(bullet[me], { x: speed * Math.cos(dir), y: speed * Math.sin(dir) });
|
||||
},
|
||||
droneRadioactive(where = {
|
||||
x: m.pos.x + 30 * Math.cos(m.angle) + 20 * (Math.random() - 0.5),
|
||||
@@ -7732,7 +7720,7 @@ const b = {
|
||||
x: m.pos.x + 30 * Math.cos(m.angle) + 10 * (Math.random() - 0.5),
|
||||
y: m.pos.y + 30 * Math.sin(m.angle) + 10 * (Math.random() - 0.5)
|
||||
}, 45)
|
||||
m.fireCDcycle = m.cycle + Math.floor(50 * b.fireCDscale); // cool down
|
||||
m.fireCDcycle = m.cycle + Math.floor(45 * b.fireCDscale); // cool down
|
||||
} else {
|
||||
b.droneRadioactive({
|
||||
x: m.pos.x + 30 * Math.cos(m.angle) + 10 * (Math.random() - 0.5),
|
||||
@@ -7743,16 +7731,16 @@ const b = {
|
||||
} else {
|
||||
if (m.crouch) {
|
||||
b.drone({
|
||||
x: m.pos.x + 30 * Math.cos(m.angle) + 10 * (Math.random() - 0.5),
|
||||
y: m.pos.y + 30 * Math.sin(m.angle) + 10 * (Math.random() - 0.5)
|
||||
}, 55)
|
||||
m.fireCDcycle = m.cycle + Math.floor(10 * b.fireCDscale); // cool down
|
||||
x: m.pos.x + 30 * Math.cos(m.angle) + 5 * (Math.random() - 0.5),
|
||||
y: m.pos.y + 30 * Math.sin(m.angle) + 5 * (Math.random() - 0.5)
|
||||
}, 50)
|
||||
m.fireCDcycle = m.cycle + Math.floor(7 * b.fireCDscale); // cool down
|
||||
} else {
|
||||
b.drone({
|
||||
x: m.pos.x + 30 * Math.cos(m.angle) + 10 * (Math.random() - 0.5),
|
||||
y: m.pos.y + 30 * Math.sin(m.angle) + 10 * (Math.random() - 0.5)
|
||||
}, 20)
|
||||
m.fireCDcycle = m.cycle + Math.floor(5 * b.fireCDscale); // cool down
|
||||
}, 15)
|
||||
m.fireCDcycle = m.cycle + Math.floor(4 * b.fireCDscale); // cool down
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7788,14 +7776,8 @@ const b = {
|
||||
const radius = 5 + 8 * Math.random() + (tech.isAmmoFoamSize && this.ammo < 300) * 12
|
||||
const SPEED = (m.crouch ? 1.2 : 1) * Math.max(2, 14 - radius * 0.25)
|
||||
const dir = m.angle + 0.15 * (Math.random() - 0.5)
|
||||
const velocity = {
|
||||
x: SPEED * Math.cos(dir),
|
||||
y: SPEED * Math.sin(dir)
|
||||
}
|
||||
const position = {
|
||||
x: m.pos.x + 30 * Math.cos(m.angle),
|
||||
y: m.pos.y + 30 * Math.sin(m.angle)
|
||||
}
|
||||
const velocity = { x: SPEED * Math.cos(dir), y: SPEED * Math.sin(dir) }
|
||||
const position = { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) }
|
||||
b.foam(position, Vector.rotate(velocity, spread), radius)
|
||||
this.applyKnock(velocity)
|
||||
m.fireCDcycle = m.cycle + Math.floor(1.5 * b.fireCDscale);
|
||||
|
||||
1044
js/level.js
1044
js/level.js
File diff suppressed because it is too large
Load Diff
@@ -12,10 +12,12 @@ const mobs = {
|
||||
}
|
||||
}
|
||||
},
|
||||
draw() {
|
||||
draw() { },
|
||||
drawDefault() {
|
||||
ctx.lineWidth = 2;
|
||||
let i = mob.length;
|
||||
while (i--) {
|
||||
// if (Matter.Query.ray(map, mob[i].position, m.pos).length === 0) { //check if there is a ray between the mob and the player
|
||||
ctx.beginPath();
|
||||
const vertices = mob[i].vertices;
|
||||
ctx.moveTo(vertices[0].x, vertices[0].y);
|
||||
@@ -25,6 +27,7 @@ const mobs = {
|
||||
ctx.strokeStyle = mob[i].stroke;
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
// }
|
||||
}
|
||||
},
|
||||
healthBar() {
|
||||
@@ -770,8 +773,8 @@ const mobs = {
|
||||
})
|
||||
} else {
|
||||
Matter.Body.setVelocity(array[i], {
|
||||
x: array[i].velocity.x * 0.94 + curlVector.x * 0.06,
|
||||
y: array[i].velocity.y * 0.94 + curlVector.y * 0.06
|
||||
x: array[i].velocity.x * 0.95 + curlVector.x * 0.06,
|
||||
y: array[i].velocity.y * 0.95 + curlVector.y * 0.06
|
||||
})
|
||||
}
|
||||
if (isAntiGravity) array[i].force.y -= 0.8 * simulation.g * array[i].mass
|
||||
|
||||
14
js/player.js
14
js/player.js
@@ -2542,8 +2542,8 @@ const m = {
|
||||
fieldUpgrades: [{
|
||||
name: "field emitter",
|
||||
imageNumber: Math.floor(Math.random() * 23),
|
||||
description: `use <strong class='color-f'>energy</strong> to <strong>deflect</strong> mobs
|
||||
<br>generate <strong>6</strong> <strong class='color-f'>energy</strong> per second`, // <br><strong>100</strong> max <strong class='color-f'>energy</strong>
|
||||
description: `<em>initial field</em><br>use <strong class='color-f'>energy</strong> to <strong>deflect</strong> mobs and <strong>throw</strong> <strong class='color-block'>blocks</strong>
|
||||
<br>generate <strong>6</strong> <strong class='color-f'>energy</strong> per second`, // <br><strong>100</strong> max <strong class='color-f'>energy</strong>
|
||||
effect: () => {
|
||||
m.hold = function () {
|
||||
if (m.isHolding) {
|
||||
@@ -4174,13 +4174,13 @@ const m = {
|
||||
{
|
||||
name: "wormhole",
|
||||
//<strong class='color-worm'>wormholes</strong> attract <strong class='color-block'>blocks</strong> and power ups<br>
|
||||
description: "use <strong class='color-f'>energy</strong> to <strong>tunnel</strong> through a <strong class='color-worm'>wormhole</strong><br><strong>+4%</strong> chance to <strong class='color-dup'>duplicate</strong> spawned <strong>power ups</strong><br>generate <strong>6</strong> <strong class='color-f'>energy</strong> per second", //<br>bullets may also traverse <strong class='color-worm'>wormholes</strong>
|
||||
description: "use <strong class='color-f'>energy</strong> to <strong>tunnel</strong> through a <strong class='color-worm'>wormhole</strong><br><strong>+5%</strong> chance to <strong class='color-dup'>duplicate</strong> spawned <strong>power ups</strong><br>generate <strong>6</strong> <strong class='color-f'>energy</strong> per second", //<br>bullets may also traverse <strong class='color-worm'>wormholes</strong>
|
||||
drain: 0,
|
||||
effect: function () {
|
||||
m.fieldMeterColor = "#bbf" //"#0c5"
|
||||
m.eyeFillColor = m.fieldMeterColor
|
||||
|
||||
m.duplicateChance = 0.04
|
||||
m.duplicateChance = 0.05
|
||||
m.fieldRange = 0
|
||||
powerUps.setPowerUpMode(); //needed after adjusting duplication chance
|
||||
|
||||
@@ -4366,7 +4366,7 @@ const m = {
|
||||
|
||||
if (input.field) {
|
||||
if (tech.isWormHolePause) {
|
||||
const drain = m.fieldRegen + 0.00004
|
||||
const drain = m.fieldRegen + 0.000035
|
||||
if (m.energy > drain) {
|
||||
m.energy -= drain
|
||||
if (m.immuneCycle < m.cycle + 1) m.immuneCycle = m.cycle + 1; //player is immune to damage for 1 cycle
|
||||
@@ -4400,9 +4400,9 @@ const m = {
|
||||
m.grabPowerUp();
|
||||
//draw possible wormhole
|
||||
if (tech.isWormholeMapIgnore && Matter.Query.ray(map, m.pos, justPastMouse).length !== 0) {
|
||||
this.drain = (0.06 + 0.006 * Math.sqrt(mag)) * 2
|
||||
this.drain = (0.05 + 0.005 * Math.sqrt(mag)) * 2
|
||||
} else {
|
||||
this.drain = tech.isFreeWormHole ? 0 : 0.06 + 0.006 * Math.sqrt(mag)
|
||||
this.drain = tech.isFreeWormHole ? 0 : 0.05 + 0.005 * Math.sqrt(mag)
|
||||
}
|
||||
const unit = Vector.perp(Vector.normalise(sub))
|
||||
const where = {
|
||||
|
||||
@@ -518,7 +518,7 @@ const powerUps = {
|
||||
m.addHealth(heal);
|
||||
if (healOutput > 0) simulation.makeTextLog(`<span class='color-var'>m</span>.health <span class='color-symbol'>+=</span> ${(healOutput).toFixed(3)}`) // <br>${m.health.toFixed(3)}
|
||||
if (tech.isOverHeal && overHeal > 0) { //tech quenching
|
||||
const scaledOverHeal = overHeal * 0.9
|
||||
const scaledOverHeal = overHeal // * 0.9
|
||||
m.damage(scaledOverHeal);
|
||||
simulation.makeTextLog(`<span class='color-var'>m</span>.health <span class='color-symbol'>-=</span> ${(scaledOverHeal).toFixed(3)}`) // <br>${m.health.toFixed(3)}
|
||||
simulation.drawList.push({ //add dmg to draw queue
|
||||
|
||||
301
js/spawn.js
301
js/spawn.js
@@ -20,9 +20,9 @@ const spawn = {
|
||||
},
|
||||
pickList: ["starter", "starter"],
|
||||
fullPickList: [
|
||||
"slasher", "slasher", "slasher2", "slasher3",
|
||||
"flutter", "flutter", "flutter",
|
||||
"hopper", "hopper", "hopper",
|
||||
"slasher", "slasher", "slasher",
|
||||
"stabber", "stabber", "stabber",
|
||||
"springer", "springer", "springer",
|
||||
"shooter", "shooter",
|
||||
@@ -30,8 +30,7 @@ const spawn = {
|
||||
"striker", "striker",
|
||||
"laser", "laser",
|
||||
"pulsar", "pulsar",
|
||||
"sneaker", "sneaker",
|
||||
"launcher", "launcherOne", "exploder", "sucker", "sniper", "spinner", "grower", "beamer", "spawner", "ghoster", "focuser"
|
||||
"sneaker", "launcher", "launcherOne", "exploder", "sucker", "sniper", "spinner", "grower", "beamer", "spawner", "ghoster", "focuser"
|
||||
],
|
||||
mobTypeSpawnOrder: [], //preset list of mob names calculated at the start of a run by the randomSeed
|
||||
mobTypeSpawnIndex: 0, //increases as the mob type cycles
|
||||
@@ -2437,7 +2436,7 @@ const spawn = {
|
||||
mobs.spawn(x, y, 5, radius, "rgb(0,200,180)");
|
||||
let me = mob[mob.length - 1];
|
||||
me.isBoss = true;
|
||||
me.damageReduction = 0.06 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
|
||||
me.damageReduction = 0.08 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
|
||||
me.accelMag = 0.05; //jump height
|
||||
me.g = 0.003; //required if using this.gravity
|
||||
me.frictionAir = 0.01;
|
||||
@@ -2736,7 +2735,7 @@ const spawn = {
|
||||
|
||||
me.stroke = "transparent"; //used for drawSneaker
|
||||
me.eventHorizon = 1100; //required for black hole
|
||||
me.seeAtDistance2 = (me.eventHorizon + 1200) * (me.eventHorizon + 1200); //vision limit is event horizon
|
||||
me.seeAtDistance2 = (me.eventHorizon + 3000) * (me.eventHorizon + 3000); //vision limit is event horizon
|
||||
me.accelMag = 0.00004 * simulation.accelScale;
|
||||
me.collisionFilter.mask = cat.player | cat.bullet //| cat.body
|
||||
// me.frictionAir = 0.005;
|
||||
@@ -2848,6 +2847,15 @@ const spawn = {
|
||||
ctx.fill();
|
||||
}
|
||||
this.curl(eventHorizon);
|
||||
//attract other power ups
|
||||
for (let i = 0; i < powerUp.length; i++) { //attract heal power ups
|
||||
const sub = Vector.sub(this.position, powerUp[i].position)
|
||||
const mag = 0.0015 * Math.min(1, (Vector.magnitude(sub) - 200) / this.eventHorizon)
|
||||
const attract = Vector.mult(Vector.normalise(sub), mag * powerUp[i].mass)
|
||||
powerUp[i].force.x += attract.x;
|
||||
powerUp[i].force.y += attract.y - powerUp[i].mass * simulation.g; //negate gravity
|
||||
// Matter.Body.setVelocity(powerUp[i], Vector.mult(powerUp[i].velocity, 0.7));
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -5493,7 +5501,7 @@ const spawn = {
|
||||
ctx.setLineDash([]);
|
||||
}
|
||||
},
|
||||
slasher(x, y, radius = 36 + Math.ceil(Math.random() * 25)) {
|
||||
slasher(x, y, radius = 33 + Math.ceil(Math.random() * 30)) {
|
||||
mobs.spawn(x, y, 5, radius, "rgb(201,202,225)");
|
||||
let me = mob[mob.length - 1];
|
||||
Matter.Body.rotate(me, 2 * Math.PI * Math.random());
|
||||
@@ -5537,10 +5545,8 @@ const spawn = {
|
||||
this.swordVertex = i
|
||||
}
|
||||
}
|
||||
// this.laserAngle = 7 / 10 * Math.PI + this.swordVertex / 5 * 2 * Math.PI - Math.PI / 2
|
||||
this.laserAngle = this.swordVertex / 5 * 2 * Math.PI + 0.6283
|
||||
this.sword = this.swordGrow
|
||||
// Matter.Body.setVelocity(this, { x: 0, y: 0 });
|
||||
this.accelMag = 0
|
||||
}
|
||||
}
|
||||
@@ -5617,6 +5623,260 @@ const spawn = {
|
||||
ctx.setLineDash([]);
|
||||
}
|
||||
},
|
||||
slasher2(x, y, radius = 33 + Math.ceil(Math.random() * 30)) {
|
||||
mobs.spawn(x, y, 6, radius, "rgb(180,199,245)");
|
||||
let me = mob[mob.length - 1];
|
||||
Matter.Body.rotate(me, 2 * Math.PI * Math.random());
|
||||
me.accelMag = 0.0009 * simulation.accelScale;
|
||||
me.torqueMagnitude = -0.000012 * me.inertia //* (Math.random() > 0.5 ? -1 : 1);
|
||||
me.frictionStatic = 0;
|
||||
me.friction = 0;
|
||||
me.frictionAir = 0.035;
|
||||
me.delay = 140 * simulation.CDScale;
|
||||
me.cd = 0;
|
||||
me.swordRadius = 0;
|
||||
me.swordVertex = 1
|
||||
me.swordRadiusMax = 275 + 3.5 * simulation.difficulty;
|
||||
me.swordRadiusGrowRate = me.swordRadiusMax * (0.011 + 0.0002 * simulation.difficulty)
|
||||
me.isSlashing = false;
|
||||
me.swordDamage = 0.03 * simulation.dmgScale
|
||||
me.laserAngle = 3 * Math.PI / 5
|
||||
const seeDistance2 = 200000
|
||||
spawn.shield(me, x, y);
|
||||
me.onDamage = function () { };
|
||||
me.do = function () {
|
||||
this.checkStatus();
|
||||
this.seePlayerByHistory(15);
|
||||
this.attraction();
|
||||
this.sword() //does various things depending on what stage of the sword swing
|
||||
};
|
||||
me.swordWaiting = function () {
|
||||
if (
|
||||
this.seePlayer.recall &&
|
||||
this.cd < simulation.cycle &&
|
||||
this.distanceToPlayer2() < seeDistance2 &&
|
||||
Matter.Query.ray(map, this.position, this.playerPosRandomY()).length === 0 &&
|
||||
Matter.Query.ray(body, this.position, this.playerPosRandomY()).length === 0
|
||||
) {
|
||||
this.laserAngle = -Math.PI / 6
|
||||
this.sword = this.swordGrow
|
||||
this.accelMag = 0
|
||||
}
|
||||
}
|
||||
me.sword = me.swordWaiting //base function that changes during different aspects of the sword swing
|
||||
me.swordGrow = function () {
|
||||
this.laserSword(this.vertices[0], this.angle + this.laserAngle);
|
||||
this.laserSword(this.vertices[3], this.angle + this.laserAngle + Math.PI);
|
||||
this.swordRadius += this.swordRadiusGrowRate
|
||||
if (this.swordRadius > this.swordRadiusMax || this.isStunned) {
|
||||
this.sword = this.swordSlash
|
||||
this.spinCount = 0
|
||||
}
|
||||
}
|
||||
me.swordSlash = function () {
|
||||
this.laserSword(this.vertices[0], this.angle + this.laserAngle);
|
||||
this.laserSword(this.vertices[3], this.angle + this.laserAngle + Math.PI);
|
||||
|
||||
this.torque += this.torqueMagnitude;
|
||||
this.spinCount++
|
||||
if (this.spinCount > 100 || this.isStunned) {
|
||||
this.sword = this.swordWaiting
|
||||
this.swordRadius = 0
|
||||
this.accelMag = 0.001 * simulation.accelScale;
|
||||
this.cd = simulation.cycle + this.delay;
|
||||
}
|
||||
}
|
||||
me.laserSword = function (where, angle) {
|
||||
const vertexCollision = function (v1, v1End, domain) {
|
||||
for (let i = 0; i < domain.length; ++i) {
|
||||
let v = domain[i].vertices;
|
||||
const len = v.length - 1;
|
||||
for (let j = 0; j < len; j++) {
|
||||
results = simulation.checkLineIntersection(v1, v1End, v[j], v[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: v[j], v2: v[j + 1] };
|
||||
}
|
||||
}
|
||||
results = simulation.checkLineIntersection(v1, v1End, v[0], v[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: v[0], v2: v[len] };
|
||||
}
|
||||
}
|
||||
};
|
||||
best = { x: null, y: null, dist2: Infinity, who: null, v1: null, v2: null };
|
||||
const look = { x: where.x + this.swordRadius * Math.cos(angle), y: where.y + this.swordRadius * Math.sin(angle) };
|
||||
vertexCollision(where, look, body); // vertexCollision(where, look, mob);
|
||||
vertexCollision(where, look, map);
|
||||
if (!m.isCloak) vertexCollision(where, look, [playerBody, playerHead]);
|
||||
if (best.who && (best.who === playerBody || best.who === playerHead) && m.immuneCycle < m.cycle) {
|
||||
m.immuneCycle = m.cycle + m.collisionImmuneCycles + 60; //player is immune to damage for an extra second
|
||||
m.damage(this.swordDamage);
|
||||
simulation.drawList.push({ //add dmg to draw queue
|
||||
x: best.x,
|
||||
y: best.y,
|
||||
radius: this.swordDamage * 1500,
|
||||
color: "rgba(80,0,255,0.5)",
|
||||
time: 20
|
||||
});
|
||||
}
|
||||
if (best.dist2 === Infinity) best = look;
|
||||
ctx.beginPath(); //draw beam
|
||||
ctx.moveTo(where.x, where.y);
|
||||
ctx.lineTo(best.x, best.y);
|
||||
ctx.strokeStyle = "rgba(100,100,255,0.1)"; // Purple path
|
||||
ctx.lineWidth = 15;
|
||||
ctx.stroke();
|
||||
ctx.strokeStyle = "rgba(100,100,255,0.5)"; // Purple path
|
||||
ctx.lineWidth = 4;
|
||||
ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]);
|
||||
ctx.stroke(); // Draw it
|
||||
ctx.setLineDash([]);
|
||||
}
|
||||
},
|
||||
slasher3(x, y, radius = 33 + Math.ceil(Math.random() * 30)) {
|
||||
const sides = 6
|
||||
mobs.spawn(x, y, sides, radius, "rgb(180,215,235)");
|
||||
let me = mob[mob.length - 1];
|
||||
Matter.Body.rotate(me, 2 * Math.PI * Math.random());
|
||||
me.accelMag = 0.0005 * simulation.accelScale;
|
||||
me.frictionStatic = 0;
|
||||
me.friction = 0;
|
||||
me.frictionAir = 0.02;
|
||||
me.delay = 150 * simulation.CDScale;
|
||||
me.cd = 0;
|
||||
me.cycle = 0;
|
||||
me.swordVertex = 1
|
||||
me.swordRadiusInitial = radius / 2;
|
||||
me.swordRadius = me.swordRadiusInitial;
|
||||
me.swordRadiusMax = 750 + 6 * simulation.difficulty;
|
||||
me.swordRadiusGrowRateInitial = 1.08
|
||||
me.swordRadiusGrowRate = me.swordRadiusGrowRateInitial//me.swordRadiusMax * (0.009 + 0.0002 * simulation.difficulty)
|
||||
me.isSlashing = false;
|
||||
me.swordDamage = 0.04 * simulation.dmgScale
|
||||
me.laserAngle = 3 * Math.PI / 5
|
||||
const seeDistance2 = me.swordRadiusMax * me.swordRadiusMax
|
||||
spawn.shield(me, x, y);
|
||||
me.onDamage = function () { };
|
||||
me.do = function () {
|
||||
this.checkStatus();
|
||||
this.seePlayerByHistory(15);
|
||||
this.sword() //does various things depending on what stage of the sword swing
|
||||
};
|
||||
me.swordWaiting = function () {
|
||||
this.attraction();
|
||||
if (
|
||||
this.seePlayer.recall &&
|
||||
this.cd < simulation.cycle &&
|
||||
this.distanceToPlayer2() < seeDistance2 &&
|
||||
Matter.Query.ray(map, this.position, this.playerPosRandomY()).length === 0 &&
|
||||
Matter.Query.ray(body, this.position, this.playerPosRandomY()).length === 0
|
||||
) {
|
||||
//find vertex closest to the player
|
||||
let dist = Infinity
|
||||
for (let i = 0, len = this.vertices.length; i < len; i++) {
|
||||
const D = Vector.magnitudeSquared(Vector.sub({ x: this.vertices[i].x, y: this.vertices[i].y }, m.pos))
|
||||
if (D < dist) {
|
||||
dist = D
|
||||
this.swordVertex = i
|
||||
}
|
||||
}
|
||||
this.laserAngle = this.swordVertex / sides * 2 * Math.PI + Math.PI / sides
|
||||
this.sword = this.swordGrow
|
||||
this.cycle = 0
|
||||
this.swordRadius = this.swordRadiusInitial
|
||||
//slow velocity but don't stop
|
||||
Matter.Body.setVelocity(this, Vector.mult(this.velocity, 0.5))
|
||||
//set angular velocity to 50%
|
||||
// Matter.Body.setAngularVelocity(this, this.angularVelocity * 0.5)
|
||||
//gently rotate towards the player with a torque, use cross product to decided clockwise or counterclockwise
|
||||
const laserStartVector = Vector.sub(this.position, this.vertices[this.swordVertex])
|
||||
const playerVector = Vector.sub(this.position, m.pos)
|
||||
const cross = Matter.Vector.cross(laserStartVector, playerVector)
|
||||
this.torque = 0.00002 * this.inertia * (cross > 0 ? 1 : -1)
|
||||
}
|
||||
}
|
||||
me.sword = me.swordWaiting //base function that changes during different aspects of the sword swing
|
||||
me.swordGrow = function () {
|
||||
this.laserSpear(this.vertices[this.swordVertex], this.angle + this.laserAngle);
|
||||
Matter.Body.setVelocity(this, Vector.mult(this.velocity, 0.9))
|
||||
// this.swordRadius += this.swordRadiusGrowRate
|
||||
this.cycle++
|
||||
// this.swordRadius = this.swordRadiusMax * Math.sin(this.cycle * 0.03)
|
||||
this.swordRadius *= this.swordRadiusGrowRate
|
||||
|
||||
if (this.swordRadius > this.swordRadiusMax) this.swordRadiusGrowRate = 1 / this.swordRadiusGrowRateInitial
|
||||
// if (this.swordRadius > this.swordRadiusMax) this.swordRadiusGrowRate = -Math.abs(this.swordRadiusGrowRate)
|
||||
if (this.swordRadius < this.swordRadiusInitial || this.isStunned) {
|
||||
// this.swordRadiusGrowRate = Math.abs(this.swordRadiusGrowRate)
|
||||
this.swordRadiusGrowRate = this.swordRadiusGrowRateInitial
|
||||
this.sword = this.swordWaiting
|
||||
this.swordRadius = 0
|
||||
this.cd = simulation.cycle + this.delay;
|
||||
}
|
||||
}
|
||||
me.laserSpear = function (where, angle) {
|
||||
const vertexCollision = function (v1, v1End, domain) {
|
||||
for (let i = 0; i < domain.length; ++i) {
|
||||
let v = domain[i].vertices;
|
||||
const len = v.length - 1;
|
||||
for (let j = 0; j < len; j++) {
|
||||
results = simulation.checkLineIntersection(v1, v1End, v[j], v[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: v[j], v2: v[j + 1] };
|
||||
}
|
||||
}
|
||||
results = simulation.checkLineIntersection(v1, v1End, v[0], v[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: v[0], v2: v[len] };
|
||||
}
|
||||
}
|
||||
};
|
||||
best = { x: null, y: null, dist2: Infinity, who: null, v1: null, v2: null };
|
||||
const look = { x: where.x + this.swordRadius * Math.cos(angle), y: where.y + this.swordRadius * Math.sin(angle) };
|
||||
vertexCollision(where, look, body); // vertexCollision(where, look, mob);
|
||||
vertexCollision(where, look, map);
|
||||
if (!m.isCloak) vertexCollision(where, look, [playerBody, playerHead]);
|
||||
if (best.who && (best.who === playerBody || best.who === playerHead)) {
|
||||
this.swordRadiusGrowRate = 1 / this.swordRadiusGrowRateInitial //!!!! this retracts the sword if it hits the player
|
||||
|
||||
if (m.immuneCycle < m.cycle) {
|
||||
m.immuneCycle = m.cycle + m.collisionImmuneCycles + 60; //player is immune to damage for an extra second
|
||||
m.damage(this.swordDamage);
|
||||
simulation.drawList.push({ //add dmg to draw queue
|
||||
x: best.x,
|
||||
y: best.y,
|
||||
radius: this.swordDamage * 1500,
|
||||
color: "rgba(80,0,255,0.5)",
|
||||
time: 20
|
||||
});
|
||||
}
|
||||
}
|
||||
if (best.dist2 === Infinity) best = look;
|
||||
ctx.beginPath(); //draw beam
|
||||
ctx.moveTo(where.x, where.y);
|
||||
ctx.lineTo(best.x, best.y);
|
||||
ctx.strokeStyle = "rgba(100,100,255,0.1)"; // Purple path
|
||||
ctx.lineWidth = 15;
|
||||
ctx.stroke();
|
||||
ctx.strokeStyle = "rgba(100,100,255,0.5)"; // Purple path
|
||||
ctx.lineWidth = 4;
|
||||
ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]);
|
||||
ctx.stroke(); // Draw it
|
||||
ctx.setLineDash([]);
|
||||
}
|
||||
},
|
||||
sneakBoss(x, y, radius = 70) {
|
||||
mobs.spawn(x, y, 5, radius, "transparent");
|
||||
let me = mob[mob.length - 1];
|
||||
@@ -5961,10 +6221,7 @@ const spawn = {
|
||||
me.friction = 0;
|
||||
me.frictionAir = 0.05;
|
||||
me.lookTorque = 0.0000025 * (Math.random() > 0.5 ? -1 : 1);
|
||||
me.fireDir = {
|
||||
x: 0,
|
||||
y: 0
|
||||
};
|
||||
me.fireDir = { x: 0, y: 0 };
|
||||
me.onDeath = function () { //helps collisions functions work better after vertex have been changed
|
||||
// this.vertices = Matter.Vertices.hull(Matter.Vertices.clockwiseSort(this.vertices))
|
||||
}
|
||||
@@ -5998,7 +6255,7 @@ const spawn = {
|
||||
me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front
|
||||
me.isVerticesChange = true
|
||||
me.memory = 240;
|
||||
me.fireFreq = 0.009 + 0.0004 * Math.min(40, simulation.difficulty); //bigger number means more shots per second
|
||||
me.fireFreq = 0.01 + 0.0005 * Math.min(40, simulation.difficulty); //bigger number means more shots per second
|
||||
me.noseLength = 0;
|
||||
me.fireAngle = 0;
|
||||
me.accelMag = 0.005 * simulation.accelScale;
|
||||
@@ -6027,14 +6284,11 @@ const spawn = {
|
||||
//set direction to turn to fire
|
||||
if (!(simulation.cycle % this.seePlayerFreq)) {
|
||||
this.fireDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position));
|
||||
this.fireDir.y -= Math.abs(this.seePlayer.position.x - this.position.x) / 2500; //gives the bullet an arc //was / 1600
|
||||
this.fireDir.y -= Math.abs(this.seePlayer.position.x - this.position.x) / 5000; //gives the bullet an arc //was / 1600
|
||||
}
|
||||
//rotate towards fireAngle
|
||||
const angle = this.angle + Math.PI / 2;
|
||||
const dot = Vector.dot({
|
||||
x: Math.cos(angle),
|
||||
y: Math.sin(angle)
|
||||
}, this.fireDir)
|
||||
const dot = Vector.dot({ x: Math.cos(angle), y: Math.sin(angle) }, this.fireDir)
|
||||
// c = Math.cos(angle) * this.fireDir.x + Math.sin(angle) * this.fireDir.y;
|
||||
const threshold = 0.1;
|
||||
if (dot > threshold) {
|
||||
@@ -6044,12 +6298,9 @@ const spawn = {
|
||||
} else if (this.noseLength > 1.5 && dot > -0.2 && dot < 0.2) {
|
||||
//fire
|
||||
for (let i = 0, len = 2 + 0.07 * simulation.difficulty; i < len; i++) {
|
||||
spawn.bullet(this.vertices[1].x, this.vertices[1].y, 7 + Math.ceil(this.radius / 25));
|
||||
const spread = Vector.rotate({
|
||||
x: Math.sqrt(len) + 4,
|
||||
y: 0
|
||||
}, 2 * Math.PI * Math.random())
|
||||
const dir = Vector.add(Vector.mult(this.fireDir, 15), spread)
|
||||
spawn.bullet(this.vertices[1].x, this.vertices[1].y, 10 + Math.ceil(this.radius / 25));
|
||||
const spread = Vector.rotate({ x: Math.sqrt(len) + 4, y: 0 }, 2 * Math.PI * Math.random())
|
||||
const dir = Vector.add(Vector.mult(this.fireDir, 25), spread)
|
||||
Matter.Body.setVelocity(mob[mob.length - 1], dir);
|
||||
}
|
||||
this.noseLength = 0;
|
||||
@@ -7326,7 +7577,7 @@ const spawn = {
|
||||
mobs.spawn(x, y, 8, radius, "rgba(0,180,180,0.4)");
|
||||
let me = mob[mob.length - 1];
|
||||
me.collisionFilter.mask = cat.bullet | cat.player //| cat.mob //| cat.body
|
||||
me.damageReduction = 0.024
|
||||
me.damageReduction = 0.028
|
||||
Matter.Body.setDensity(me, 0.0001); //normal is 0.001
|
||||
|
||||
// me.accelMag = 0.0007 * simulation.accelScale;
|
||||
|
||||
59
js/tech.js
59
js/tech.js
@@ -325,7 +325,7 @@ const tech = {
|
||||
tech.hardLanding = 70
|
||||
tech.isFallingDamage = true;
|
||||
m.setMaxHealth();
|
||||
m.addHealth(1 / simulation.healScale)
|
||||
m.addHealth(2.22 / simulation.healScale)
|
||||
m.skin.tungsten()
|
||||
},
|
||||
remove() {
|
||||
@@ -3013,7 +3013,10 @@ const tech = {
|
||||
},
|
||||
{
|
||||
name: "induction brake",
|
||||
description: `after using ${powerUps.orb.heal()} <strong class='color-s'>slow</strong> nearby mobs for <strong>15</strong> seconds<br>spawn ${powerUps.orb.heal(4)}`,
|
||||
descriptionFunction() {
|
||||
return `after using ${powerUps.orb.heal()} <strong class='color-s'>slow</strong> nearby mobs for <strong>15</strong> seconds<br>spawn ${powerUps.orb.heal(4)}`
|
||||
},
|
||||
// description: `after using ${powerUps.orb.heal()} <strong class='color-s'>slow</strong> nearby mobs for <strong>15</strong> seconds<br>spawn ${powerUps.orb.heal(4)}`,
|
||||
maxCount: 1,
|
||||
count: 0,
|
||||
frequency: 1,
|
||||
@@ -3096,7 +3099,10 @@ const tech = {
|
||||
},
|
||||
{
|
||||
name: "accretion",
|
||||
description: `${powerUps.orb.heal(1)} follow you, even between levels<br>spawn ${powerUps.orb.heal(5)}`,
|
||||
descriptionFunction() {
|
||||
return `${powerUps.orb.heal(1)} follow you, even between levels<br>spawn ${powerUps.orb.heal(5)}`
|
||||
},
|
||||
// description: `${powerUps.orb.heal(1)} follow you, even between levels<br>spawn ${powerUps.orb.heal(5)}`,
|
||||
maxCount: 1,
|
||||
count: 0,
|
||||
frequency: 1,
|
||||
@@ -3270,7 +3276,7 @@ const tech = {
|
||||
},
|
||||
{
|
||||
name: "Hilbert space",
|
||||
description: "<strong>+91%</strong> <strong class='color-d'>damage</strong><br>after a <strong>collision</strong> enter an <strong class='alt'>alternate reality</strong>",
|
||||
description: "<strong>+99%</strong> <strong class='color-d'>damage</strong><br>after a <strong>collision</strong> enter an <strong class='alt'>alternate reality</strong>",
|
||||
maxCount: 1,
|
||||
count: 0,
|
||||
frequency: 1,
|
||||
@@ -3280,7 +3286,7 @@ const tech = {
|
||||
return !tech.isResearchReality && !tech.isSwitchReality
|
||||
},
|
||||
requires: "not Ψ(t) collapse, many-worlds",
|
||||
damage: 1.91,
|
||||
damage: 1.99,
|
||||
effect() {
|
||||
tech.damage *= this.damage
|
||||
tech.isCollisionRealitySwitch = true;
|
||||
@@ -3454,7 +3460,10 @@ const tech = {
|
||||
},
|
||||
{
|
||||
name: "mass production",
|
||||
description: `<strong class='color-m'>tech</strong> always have <strong>+3</strong> choices to spawn<br>${powerUps.orb.research(5)} ${powerUps.orb.ammo(8)} or ${powerUps.orb.heal(8)}`,
|
||||
descriptionFunction() {
|
||||
return `<strong class='color-m'>tech</strong> always have <strong>+3</strong> choices to spawn<br>${powerUps.orb.ammo(8)} ${powerUps.orb.heal(8)} or ${powerUps.orb.research(5)}`
|
||||
},
|
||||
// description: `<strong class='color-m'>tech</strong> always have <strong>+3</strong> choices to spawn<br>${powerUps.orb.ammo(8)} ${powerUps.orb.heal(8)} or ${powerUps.orb.research(5)}`,
|
||||
maxCount: 1,
|
||||
count: 0,
|
||||
frequency: 1,
|
||||
@@ -3502,7 +3511,9 @@ const tech = {
|
||||
},
|
||||
{
|
||||
name: "heals",
|
||||
description: `spawn ${powerUps.orb.heal(8)}`,
|
||||
descriptionFunction() {
|
||||
return `spawn ${powerUps.orb.heal(8)}`
|
||||
},
|
||||
maxCount: 1,
|
||||
count: 0,
|
||||
frequency: 0,
|
||||
@@ -9036,7 +9047,7 @@ const tech = {
|
||||
// },
|
||||
{
|
||||
name: "return",
|
||||
description: "return to the introduction level<br>reduce combat <strong>difficulty</strong> by <strong>2 levels</strong>",
|
||||
description: "return to the start of the game<br>reduce combat <strong>difficulty</strong> by <strong>2 levels</strong>",
|
||||
maxCount: 1,
|
||||
count: 0,
|
||||
frequency: 0,
|
||||
@@ -9500,21 +9511,7 @@ const tech = {
|
||||
}
|
||||
},
|
||||
remove() {
|
||||
mobs.draw = () => {
|
||||
ctx.lineWidth = 2;
|
||||
let i = mob.length;
|
||||
while (i--) {
|
||||
ctx.beginPath();
|
||||
const vertices = mob[i].vertices;
|
||||
ctx.moveTo(vertices[0].x, vertices[0].y);
|
||||
for (let j = 1, len = vertices.length; j < len; ++j) ctx.lineTo(vertices[j].x, vertices[j].y);
|
||||
ctx.lineTo(vertices[0].x, vertices[0].y);
|
||||
ctx.fillStyle = mob[i].fill;
|
||||
ctx.strokeStyle = mob[i].stroke;
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
mobs.draw = mobs.drawDefault
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -9546,21 +9543,7 @@ const tech = {
|
||||
}
|
||||
},
|
||||
remove() {
|
||||
mobs.draw = () => {
|
||||
ctx.lineWidth = 2;
|
||||
let i = mob.length;
|
||||
while (i--) {
|
||||
ctx.beginPath();
|
||||
const vertices = mob[i].vertices;
|
||||
ctx.moveTo(vertices[0].x, vertices[0].y);
|
||||
for (let j = 1, len = vertices.length; j < len; ++j) ctx.lineTo(vertices[j].x, vertices[j].y);
|
||||
ctx.lineTo(vertices[0].x, vertices[0].y);
|
||||
ctx.fillStyle = mob[i].fill;
|
||||
ctx.strokeStyle = mob[i].stroke;
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
mobs.draw = mobs.drawDefault
|
||||
}
|
||||
},
|
||||
// draw() {
|
||||
|
||||
Reference in New Issue
Block a user