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:
landgreen
2023-07-27 10:10:33 -07:00
parent 8a211e81ec
commit 3d423a58d6
8 changed files with 1033 additions and 518 deletions

View File

@@ -2832,19 +2832,13 @@ const b = {
} }
if (tech.isLaserPush) { //push mobs away if (tech.isLaserPush) { //push mobs away
const index = path.length - 1 const index = path.length - 1
Matter.Body.setVelocity(best.who, { Matter.Body.setVelocity(best.who, { x: best.who.velocity.x * 0.97, y: best.who.velocity.y * 0.97 });
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)) 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) Matter.Body.applyForce(best.who, path[index], force)
} }
} else if (tech.isLaserPush && best.who.classType === "body") { } else if (tech.isLaserPush && best.who.classType === "body") {
const index = path.length - 1 const index = path.length - 1
Matter.Body.setVelocity(best.who, { Matter.Body.setVelocity(best.who, { x: best.who.velocity.x * 0.97, y: best.who.velocity.y * 0.97 });
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)) 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) Matter.Body.applyForce(best.who, path[index], force)
} }
@@ -3679,7 +3673,7 @@ const b = {
}, speed = 1) { }, speed = 1) {
const me = bullet.length; const me = bullet.length;
const THRUST = 0.0015 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()) const RADIUS = (4.5 + 3 * Math.random())
bullet[me] = Bodies.polygon(where.x, where.y, 8, RADIUS, { bullet[me] = Bodies.polygon(where.x, where.y, 8, RADIUS, {
angle: dir, angle: dir,
@@ -3822,7 +3816,7 @@ const b = {
!mob[i].isInvulnerable !mob[i].isInvulnerable
) { ) {
const TARGET_VECTOR = Vector.sub(this.position, mob[i].position) 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) { if (DIST < closeDist) {
closeDist = DIST; closeDist = DIST;
this.lockedOn = mob[i] this.lockedOn = mob[i]
@@ -3931,18 +3925,12 @@ const b = {
} }
// speed cap instead of friction to give more agility // speed cap instead of friction to give more agility
if (this.speed > 6) { if (this.speed > 6) {
Matter.Body.setVelocity(this, { Matter.Body.setVelocity(this, { x: this.velocity.x * 0.97, y: this.velocity.y * 0.97 });
x: this.velocity.x * 0.97,
y: this.velocity.y * 0.97
});
} }
} }
}) })
Composite.add(engine.world, bullet[me]); //add bullet to world Composite.add(engine.world, bullet[me]); //add bullet to world
Matter.Body.setVelocity(bullet[me], { Matter.Body.setVelocity(bullet[me], { x: speed * Math.cos(dir), y: speed * Math.sin(dir) });
x: speed * Math.cos(dir),
y: speed * Math.sin(dir)
});
}, },
droneRadioactive(where = { droneRadioactive(where = {
x: m.pos.x + 30 * Math.cos(m.angle) + 20 * (Math.random() - 0.5), 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), 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) y: m.pos.y + 30 * Math.sin(m.angle) + 10 * (Math.random() - 0.5)
}, 45) }, 45)
m.fireCDcycle = m.cycle + Math.floor(50 * b.fireCDscale); // cool down m.fireCDcycle = m.cycle + Math.floor(45 * b.fireCDscale); // cool down
} else { } else {
b.droneRadioactive({ b.droneRadioactive({
x: m.pos.x + 30 * Math.cos(m.angle) + 10 * (Math.random() - 0.5), x: m.pos.x + 30 * Math.cos(m.angle) + 10 * (Math.random() - 0.5),
@@ -7743,16 +7731,16 @@ const b = {
} else { } else {
if (m.crouch) { if (m.crouch) {
b.drone({ b.drone({
x: m.pos.x + 30 * Math.cos(m.angle) + 10 * (Math.random() - 0.5), x: m.pos.x + 30 * Math.cos(m.angle) + 5 * (Math.random() - 0.5),
y: m.pos.y + 30 * Math.sin(m.angle) + 10 * (Math.random() - 0.5) y: m.pos.y + 30 * Math.sin(m.angle) + 5 * (Math.random() - 0.5)
}, 55) }, 50)
m.fireCDcycle = m.cycle + Math.floor(10 * b.fireCDscale); // cool down m.fireCDcycle = m.cycle + Math.floor(7 * b.fireCDscale); // cool down
} else { } else {
b.drone({ b.drone({
x: m.pos.x + 30 * Math.cos(m.angle) + 10 * (Math.random() - 0.5), 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) y: m.pos.y + 30 * Math.sin(m.angle) + 10 * (Math.random() - 0.5)
}, 20) }, 15)
m.fireCDcycle = m.cycle + Math.floor(5 * b.fireCDscale); // cool down 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 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 SPEED = (m.crouch ? 1.2 : 1) * Math.max(2, 14 - radius * 0.25)
const dir = m.angle + 0.15 * (Math.random() - 0.5) const dir = m.angle + 0.15 * (Math.random() - 0.5)
const velocity = { const velocity = { x: SPEED * Math.cos(dir), y: SPEED * Math.sin(dir) }
x: SPEED * Math.cos(dir), const position = { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) }
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) b.foam(position, Vector.rotate(velocity, spread), radius)
this.applyKnock(velocity) this.applyKnock(velocity)
m.fireCDcycle = m.cycle + Math.floor(1.5 * b.fireCDscale); m.fireCDcycle = m.cycle + Math.floor(1.5 * b.fireCDscale);

File diff suppressed because it is too large Load Diff

View File

@@ -12,10 +12,12 @@ const mobs = {
} }
} }
}, },
draw() { draw() { },
drawDefault() {
ctx.lineWidth = 2; ctx.lineWidth = 2;
let i = mob.length; let i = mob.length;
while (i--) { 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(); ctx.beginPath();
const vertices = mob[i].vertices; const vertices = mob[i].vertices;
ctx.moveTo(vertices[0].x, vertices[0].y); ctx.moveTo(vertices[0].x, vertices[0].y);
@@ -25,6 +27,7 @@ const mobs = {
ctx.strokeStyle = mob[i].stroke; ctx.strokeStyle = mob[i].stroke;
ctx.fill(); ctx.fill();
ctx.stroke(); ctx.stroke();
// }
} }
}, },
healthBar() { healthBar() {
@@ -770,8 +773,8 @@ const mobs = {
}) })
} else { } else {
Matter.Body.setVelocity(array[i], { Matter.Body.setVelocity(array[i], {
x: array[i].velocity.x * 0.94 + curlVector.x * 0.06, x: array[i].velocity.x * 0.95 + curlVector.x * 0.06,
y: array[i].velocity.y * 0.94 + curlVector.y * 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 if (isAntiGravity) array[i].force.y -= 0.8 * simulation.g * array[i].mass

View File

@@ -2542,8 +2542,8 @@ const m = {
fieldUpgrades: [{ fieldUpgrades: [{
name: "field emitter", name: "field emitter",
imageNumber: Math.floor(Math.random() * 23), imageNumber: Math.floor(Math.random() * 23),
description: `use <strong class='color-f'>energy</strong> to <strong>deflect</strong> mobs 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> <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: () => { effect: () => {
m.hold = function () { m.hold = function () {
if (m.isHolding) { if (m.isHolding) {
@@ -4174,13 +4174,13 @@ const m = {
{ {
name: "wormhole", name: "wormhole",
//<strong class='color-worm'>wormholes</strong> attract <strong class='color-block'>blocks</strong> and power ups<br> //<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, drain: 0,
effect: function () { effect: function () {
m.fieldMeterColor = "#bbf" //"#0c5" m.fieldMeterColor = "#bbf" //"#0c5"
m.eyeFillColor = m.fieldMeterColor m.eyeFillColor = m.fieldMeterColor
m.duplicateChance = 0.04 m.duplicateChance = 0.05
m.fieldRange = 0 m.fieldRange = 0
powerUps.setPowerUpMode(); //needed after adjusting duplication chance powerUps.setPowerUpMode(); //needed after adjusting duplication chance
@@ -4366,7 +4366,7 @@ const m = {
if (input.field) { if (input.field) {
if (tech.isWormHolePause) { if (tech.isWormHolePause) {
const drain = m.fieldRegen + 0.00004 const drain = m.fieldRegen + 0.000035
if (m.energy > drain) { if (m.energy > drain) {
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 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(); m.grabPowerUp();
//draw possible wormhole //draw possible wormhole
if (tech.isWormholeMapIgnore && Matter.Query.ray(map, m.pos, justPastMouse).length !== 0) { 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 { } 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 unit = Vector.perp(Vector.normalise(sub))
const where = { const where = {

View File

@@ -518,7 +518,7 @@ const powerUps = {
m.addHealth(heal); 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 (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 if (tech.isOverHeal && overHeal > 0) { //tech quenching
const scaledOverHeal = overHeal * 0.9 const scaledOverHeal = overHeal // * 0.9
m.damage(scaledOverHeal); 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.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 simulation.drawList.push({ //add dmg to draw queue

View File

@@ -20,9 +20,9 @@ const spawn = {
}, },
pickList: ["starter", "starter"], pickList: ["starter", "starter"],
fullPickList: [ fullPickList: [
"slasher", "slasher", "slasher2", "slasher3",
"flutter", "flutter", "flutter", "flutter", "flutter", "flutter",
"hopper", "hopper", "hopper", "hopper", "hopper", "hopper",
"slasher", "slasher", "slasher",
"stabber", "stabber", "stabber", "stabber", "stabber", "stabber",
"springer", "springer", "springer", "springer", "springer", "springer",
"shooter", "shooter", "shooter", "shooter",
@@ -30,8 +30,7 @@ const spawn = {
"striker", "striker", "striker", "striker",
"laser", "laser", "laser", "laser",
"pulsar", "pulsar", "pulsar", "pulsar",
"sneaker", "sneaker", "sneaker", "launcher", "launcherOne", "exploder", "sucker", "sniper", "spinner", "grower", "beamer", "spawner", "ghoster", "focuser"
"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 mobTypeSpawnOrder: [], //preset list of mob names calculated at the start of a run by the randomSeed
mobTypeSpawnIndex: 0, //increases as the mob type cycles mobTypeSpawnIndex: 0, //increases as the mob type cycles
@@ -2437,7 +2436,7 @@ const spawn = {
mobs.spawn(x, y, 5, radius, "rgb(0,200,180)"); mobs.spawn(x, y, 5, radius, "rgb(0,200,180)");
let me = mob[mob.length - 1]; let me = mob[mob.length - 1];
me.isBoss = true; 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.accelMag = 0.05; //jump height
me.g = 0.003; //required if using this.gravity me.g = 0.003; //required if using this.gravity
me.frictionAir = 0.01; me.frictionAir = 0.01;
@@ -2736,7 +2735,7 @@ const spawn = {
me.stroke = "transparent"; //used for drawSneaker me.stroke = "transparent"; //used for drawSneaker
me.eventHorizon = 1100; //required for black hole 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.accelMag = 0.00004 * simulation.accelScale;
me.collisionFilter.mask = cat.player | cat.bullet //| cat.body me.collisionFilter.mask = cat.player | cat.bullet //| cat.body
// me.frictionAir = 0.005; // me.frictionAir = 0.005;
@@ -2848,6 +2847,15 @@ const spawn = {
ctx.fill(); ctx.fill();
} }
this.curl(eventHorizon); 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([]); 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)"); mobs.spawn(x, y, 5, radius, "rgb(201,202,225)");
let me = mob[mob.length - 1]; let me = mob[mob.length - 1];
Matter.Body.rotate(me, 2 * Math.PI * Math.random()); Matter.Body.rotate(me, 2 * Math.PI * Math.random());
@@ -5537,10 +5545,8 @@ const spawn = {
this.swordVertex = i 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.laserAngle = this.swordVertex / 5 * 2 * Math.PI + 0.6283
this.sword = this.swordGrow this.sword = this.swordGrow
// Matter.Body.setVelocity(this, { x: 0, y: 0 });
this.accelMag = 0 this.accelMag = 0
} }
} }
@@ -5617,6 +5623,260 @@ const spawn = {
ctx.setLineDash([]); 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) { sneakBoss(x, y, radius = 70) {
mobs.spawn(x, y, 5, radius, "transparent"); mobs.spawn(x, y, 5, radius, "transparent");
let me = mob[mob.length - 1]; let me = mob[mob.length - 1];
@@ -5961,10 +6221,7 @@ const spawn = {
me.friction = 0; me.friction = 0;
me.frictionAir = 0.05; me.frictionAir = 0.05;
me.lookTorque = 0.0000025 * (Math.random() > 0.5 ? -1 : 1); me.lookTorque = 0.0000025 * (Math.random() > 0.5 ? -1 : 1);
me.fireDir = { me.fireDir = { x: 0, y: 0 };
x: 0,
y: 0
};
me.onDeath = function () { //helps collisions functions work better after vertex have been changed me.onDeath = function () { //helps collisions functions work better after vertex have been changed
// this.vertices = Matter.Vertices.hull(Matter.Vertices.clockwiseSort(this.vertices)) // 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.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front
me.isVerticesChange = true me.isVerticesChange = true
me.memory = 240; 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.noseLength = 0;
me.fireAngle = 0; me.fireAngle = 0;
me.accelMag = 0.005 * simulation.accelScale; me.accelMag = 0.005 * simulation.accelScale;
@@ -6027,14 +6284,11 @@ const spawn = {
//set direction to turn to fire //set direction to turn to fire
if (!(simulation.cycle % this.seePlayerFreq)) { if (!(simulation.cycle % this.seePlayerFreq)) {
this.fireDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position)); 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 //rotate towards fireAngle
const angle = this.angle + Math.PI / 2; const angle = this.angle + Math.PI / 2;
const dot = Vector.dot({ const dot = Vector.dot({ x: Math.cos(angle), y: Math.sin(angle) }, this.fireDir)
x: Math.cos(angle),
y: Math.sin(angle)
}, this.fireDir)
// c = Math.cos(angle) * this.fireDir.x + Math.sin(angle) * this.fireDir.y; // c = Math.cos(angle) * this.fireDir.x + Math.sin(angle) * this.fireDir.y;
const threshold = 0.1; const threshold = 0.1;
if (dot > threshold) { if (dot > threshold) {
@@ -6044,12 +6298,9 @@ const spawn = {
} else if (this.noseLength > 1.5 && dot > -0.2 && dot < 0.2) { } else if (this.noseLength > 1.5 && dot > -0.2 && dot < 0.2) {
//fire //fire
for (let i = 0, len = 2 + 0.07 * simulation.difficulty; i < len; i++) { 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)); spawn.bullet(this.vertices[1].x, this.vertices[1].y, 10 + Math.ceil(this.radius / 25));
const spread = Vector.rotate({ const spread = Vector.rotate({ x: Math.sqrt(len) + 4, y: 0 }, 2 * Math.PI * Math.random())
x: Math.sqrt(len) + 4, const dir = Vector.add(Vector.mult(this.fireDir, 25), spread)
y: 0
}, 2 * Math.PI * Math.random())
const dir = Vector.add(Vector.mult(this.fireDir, 15), spread)
Matter.Body.setVelocity(mob[mob.length - 1], dir); Matter.Body.setVelocity(mob[mob.length - 1], dir);
} }
this.noseLength = 0; this.noseLength = 0;
@@ -7326,7 +7577,7 @@ const spawn = {
mobs.spawn(x, y, 8, radius, "rgba(0,180,180,0.4)"); mobs.spawn(x, y, 8, radius, "rgba(0,180,180,0.4)");
let me = mob[mob.length - 1]; let me = mob[mob.length - 1];
me.collisionFilter.mask = cat.bullet | cat.player //| cat.mob //| cat.body 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 Matter.Body.setDensity(me, 0.0001); //normal is 0.001
// me.accelMag = 0.0007 * simulation.accelScale; // me.accelMag = 0.0007 * simulation.accelScale;

View File

@@ -325,7 +325,7 @@ const tech = {
tech.hardLanding = 70 tech.hardLanding = 70
tech.isFallingDamage = true; tech.isFallingDamage = true;
m.setMaxHealth(); m.setMaxHealth();
m.addHealth(1 / simulation.healScale) m.addHealth(2.22 / simulation.healScale)
m.skin.tungsten() m.skin.tungsten()
}, },
remove() { remove() {
@@ -3013,7 +3013,10 @@ const tech = {
}, },
{ {
name: "induction brake", 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, maxCount: 1,
count: 0, count: 0,
frequency: 1, frequency: 1,
@@ -3096,7 +3099,10 @@ const tech = {
}, },
{ {
name: "accretion", 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, maxCount: 1,
count: 0, count: 0,
frequency: 1, frequency: 1,
@@ -3270,7 +3276,7 @@ const tech = {
}, },
{ {
name: "Hilbert space", 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, maxCount: 1,
count: 0, count: 0,
frequency: 1, frequency: 1,
@@ -3280,7 +3286,7 @@ const tech = {
return !tech.isResearchReality && !tech.isSwitchReality return !tech.isResearchReality && !tech.isSwitchReality
}, },
requires: "not Ψ(t) collapse, many-worlds", requires: "not Ψ(t) collapse, many-worlds",
damage: 1.91, damage: 1.99,
effect() { effect() {
tech.damage *= this.damage tech.damage *= this.damage
tech.isCollisionRealitySwitch = true; tech.isCollisionRealitySwitch = true;
@@ -3454,7 +3460,10 @@ const tech = {
}, },
{ {
name: "mass production", 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 &nbsp; ${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)} &nbsp;&nbsp; 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)} &nbsp;&nbsp; or ${powerUps.orb.research(5)}`,
maxCount: 1, maxCount: 1,
count: 0, count: 0,
frequency: 1, frequency: 1,
@@ -3502,7 +3511,9 @@ const tech = {
}, },
{ {
name: "heals", name: "heals",
description: `spawn ${powerUps.orb.heal(8)}`, descriptionFunction() {
return `spawn ${powerUps.orb.heal(8)}`
},
maxCount: 1, maxCount: 1,
count: 0, count: 0,
frequency: 0, frequency: 0,
@@ -9036,7 +9047,7 @@ const tech = {
// }, // },
{ {
name: "return", 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, maxCount: 1,
count: 0, count: 0,
frequency: 0, frequency: 0,
@@ -9500,21 +9511,7 @@ const tech = {
} }
}, },
remove() { remove() {
mobs.draw = () => { mobs.draw = mobs.drawDefault
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();
}
}
} }
}, },
{ {
@@ -9546,21 +9543,7 @@ const tech = {
} }
}, },
remove() { remove() {
mobs.draw = () => { mobs.draw = mobs.drawDefault
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();
}
}
} }
}, },
// draw() { // draw() {

View File

@@ -1,15 +1,33 @@
******************************************************** NEXT PATCH ************************************************** ******************************************************** NEXT PATCH **************************************************
new community levels: new community training level diamagnetism by Richard0820
tlinat by Richard0820 it's at the end of the training levels
ruins by SiddhUPe start training by click the top right button at the load screen
tech: mass production - tech have +3 choices to spawn ammo, research, or heals 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
*********************************************************** TODO ***************************************************** *********************************************************** TODO *****************************************************
make a mob similar to slasher use cross product rotation for other mobs?
because it's just a very well made mob. snipers, shooters?
//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)
block manufacturing - molecular assembler tech
Holding r-click will create a slowly increasing in size block, which will be thrown on release
super-bot: fires super balls super-bot: fires super balls
@@ -24,8 +42,6 @@ tech: after a needle hits a mobs
reset your fire CD? reset your fire CD?
2x damage for each consecutive mob hit? 2x damage for each consecutive mob hit?
improve flatland performance?
mob non-combat behaviors, like Rain World mob non-combat behaviors, like Rain World
gathering gathering
blocks blocks
@@ -62,10 +78,6 @@ use ephemera to replace some bad code
damage and defense bars damage and defense bars
disable and enable ephemera with settings disable and enable ephemera with settings
drones target anything that moves: speed > 1
including player, blocks?, mobs, power ups
maybe target the fastest mobs?
perfect diamagnatism - invulnerable while field is active? perfect diamagnatism - invulnerable while field is active?
also drain energy while field is active? also drain energy while field is active?
@@ -75,11 +87,6 @@ mobs attack mines
tech circular polarization - wave gun bullets move in a circle tech circular polarization - wave gun bullets move in a circle
tech: choose next map by name after exiting current map
use modified tech selection code?
this might be too much work without much reward
JUNK only? or maybe combine with other buff
Tech: relativity Tech: relativity
Simulation speed scales with movement speed. When still, time moves at 0.4 speed, at full walking speed its 1. (So if youre falling or something and you move faster the simulation will be faster than usual) Simulation speed scales with movement speed. When still, time moves at 0.4 speed, at full walking speed its 1. (So if youre falling or something and you move faster the simulation will be faster than usual)
Also a damage and/or defense boost to make it worth using Also a damage and/or defense boost to make it worth using
@@ -94,7 +101,6 @@ extend brainstorming animation timers to fps cap?
perfect diamagnatism could bounce on mobs, or even map elements? perfect diamagnatism could bounce on mobs, or even map elements?
could work like a rocket jump? could work like a rocket jump?
tech: Bose Einstein condensate - freezes enemies in pilot wave, and drains some energy? tech: Bose Einstein condensate - freezes enemies in pilot wave, and drains some energy?
make super balls with Zectron deflectable with field make super balls with Zectron deflectable with field
@@ -103,17 +109,8 @@ make super balls with Zectron deflectable with field
set mob health bar colors based on status effects? set mob health bar colors based on status effects?
make mob damage immunity a mob status effect? make mob damage immunity a mob status effect?
physics notes: add link to double slit content
https://www.youtube.com/watch?v=v_uBaBuarEM
tech: rail gun area damage effect, but for all harpoon mode tech: rail gun area damage effect, but for all harpoon mode
laser momentum pushed back on player?
might just be annoying
JUNK - overwrite mob draw function so mobs only draw if they can connect a ray from player to mob
gonna cause lag?
mob status effect - vulnerability mob status effect - vulnerability
mobs take 4x damage for __ time mobs take 4x damage for __ time
afterwards mobs go back to normal damage taken afterwards mobs go back to normal damage taken
@@ -129,8 +126,6 @@ tech: sporangium that grow little trees
the trees have an area of effect damage for about 6-10 seconds the trees have an area of effect damage for about 6-10 seconds
maybe something similar to radioactive drones, but maybe a few smaller shapes maybe something similar to radioactive drones, but maybe a few smaller shapes
harpoon tech that makes auto aim work much better
hookBoss fires a hook that pulls player towards it hookBoss fires a hook that pulls player towards it
hook does a bit of damage hook does a bit of damage
player targeted unless cloaking player targeted unless cloaking
@@ -213,13 +208,9 @@ Tech:when relay switch/flip flop is on, turn ammo powerups into boosts, when rel
JUNK: what the golf? JUNK: what the golf?
trying to throw a block throws you instead trying to throw a block throws you instead
look for other tech that would benefit from a 3rd line of description text
tech for lens - you can only fire through the lens tech for lens - you can only fire through the lens
and some buff? damage or energy? and some buff? damage or energy?
hopMom fight make platforming with hop bullets harder?
complete blowSuckBoss... or don't complete blowSuckBoss... or don't
tech: laser reflections increase damage tech: laser reflections increase damage
@@ -227,14 +218,6 @@ tech: laser reflections increase damage
JUNK tech different effects based on night or day JUNK tech different effects based on night or day
use system time use system time
buffing your deflecting for 1 second after pressing the field button
2 second cooldown on the effect to prevent spamming it
buff: giving energy or doing damage makes sense
maybe this could be a rework for bremstralung
replace field descriptions with a function call so they can have dynamic text
add in dynamic coupling text as a 4th line
Boss that shoots out a ring of bullets, then after a few seconds it gravitates the bullets back Boss that shoots out a ring of bullets, then after a few seconds it gravitates the bullets back
coupling coupling
@@ -404,12 +387,6 @@ super balls do more damage after bouncing?
how to check for bounce? how to check for bounce?
maybe just increases damage after hitting a mob maybe just increases damage after hitting a mob
Make environmental damages also damage mobs
So if a mob passes through laser, it gets damaged
dark mode:
look at Tinyfolks, 20 minutes till dawn
super short range foam that acts like flame thrower super short range foam that acts like flame thrower
high fire rate high fire rate
short life spawn short life spawn
@@ -428,8 +405,7 @@ laser tech where bots move around and follow you while firing lasers in the dire
beam is similar to diffuse beam beam is similar to diffuse beam
block manufacturing - molecular assembler tech
Holding r-click will create a slowly increasing in size block, which will be thrown on release
double research double research