new level boss that fires 2 streams of small bullets that chase you

mod: add a CPT gun to your inventory that rewinds your history, reverts your health, position, velocity for 10 seconds
  I expect that spamming rewind has some overpowered combos.
  Let me know what you find, and your ideas on balance.
This commit is contained in:
landgreen
2020-12-21 12:47:07 -08:00
parent 732b13d8a4
commit 60e59a858a
10 changed files with 815 additions and 458 deletions

View File

@@ -274,6 +274,132 @@ const b = {
}
}
},
pulse(energy, angle = mech.angle) {
let best;
let explosionRange = 1560 * energy
let range = 3000
const path = [{
x: mech.pos.x + 20 * Math.cos(angle),
y: mech.pos.y + 20 * Math.sin(angle)
},
{
x: mech.pos.x + range * Math.cos(angle),
y: mech.pos.y + range * Math.sin(angle)
}
];
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 = game.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 = game.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 && (!domain[i].mob || domain[i].alive)) {
best = {
x: results.x,
y: results.y,
dist2: dist2,
who: domain[i],
v1: vertices[0],
v2: vertices[len]
};
}
}
}
};
//check for collisions
best = {
x: null,
y: null,
dist2: Infinity,
who: null,
v1: null,
v2: null
};
if (mod.isPulseAim) { //find mobs in line of sight
let dist = 2200
for (let i = 0, len = mob.length; i < len; i++) {
const newDist = Vector.magnitude(Vector.sub(path[0], mob[i].position))
if (explosionRange < newDist &&
newDist < dist &&
Matter.Query.ray(map, path[0], mob[i].position).length === 0 &&
Matter.Query.ray(body, path[0], mob[i].position).length === 0) {
dist = newDist
best.who = mob[i]
path[path.length - 1] = mob[i].position
}
}
}
if (!best.who) {
vertexCollision(path[0], path[1], mob);
vertexCollision(path[0], path[1], map);
vertexCollision(path[0], path[1], body);
if (best.dist2 != Infinity) { //if hitting something
path[path.length - 1] = {
x: best.x,
y: best.y
};
}
}
if (best.who) b.explosion(path[1], explosionRange, true)
if (mod.isPulseStun) {
const range = 100 + 2000 * energy
for (let i = 0, len = mob.length; i < len; ++i) {
if (mob[i].alive && !mob[i].isShielded) {
dist = Vector.magnitude(Vector.sub(path[1], mob[i].position)) - mob[i].radius;
if (dist < range) mobs.statusStun(mob[i], 30 + Math.floor(energy * 60))
}
}
}
//draw laser beam
ctx.beginPath();
ctx.moveTo(path[0].x, path[0].y);
ctx.lineTo(path[1].x, path[1].y);
ctx.strokeStyle = "rgba(255,0,0,0.13)"
ctx.lineWidth = 60 * energy / 0.2
ctx.stroke();
ctx.strokeStyle = "rgba(255,0,0,0.2)"
ctx.lineWidth = 18
ctx.stroke();
ctx.strokeStyle = "#f00";
ctx.lineWidth = 4
ctx.stroke();
//draw little dots along the laser path
const sub = Vector.sub(path[1], path[0])
const mag = Vector.magnitude(sub)
for (let i = 0, len = Math.floor(mag * 0.03 * energy / 0.2); i < len; i++) {
const dist = Math.random()
game.drawList.push({
x: path[0].x + sub.x * dist + 13 * (Math.random() - 0.5),
y: path[0].y + sub.y * dist + 13 * (Math.random() - 0.5),
radius: 1 + 4 * Math.random(),
color: "rgba(255,0,0,0.5)",
time: Math.floor(2 + 33 * Math.random() * Math.random())
});
}
},
grenade() {
},
@@ -550,7 +676,7 @@ const b = {
}
}
slow(body, this.damageRadius)
slow([player], this.damageRadius)
if (!mod.isNeutronImmune) slow([player], this.damageRadius)
}
}
}
@@ -591,6 +717,7 @@ const b = {
},
onEnd() {
b.explosion(this.position, this.explodeRad * size); //makes bullet do explosive damage at end
if (mod.fragments) b.targetedNail(this.position, mod.fragments * 5)
if (spawn) {
for (let i = 0; i < mod.recursiveMissiles; i++) {
if (0.2 - 0.02 * i > Math.random()) {
@@ -724,8 +851,8 @@ const b = {
const q = Matter.Query.point(mob, this.position)
for (let i = 0; i < q.length; i++) {
Matter.Body.setVelocity(q[i], {
x: q[i].velocity.x * 0.7,
y: q[i].velocity.y * 0.7
x: q[i].velocity.x * 0.6,
y: q[i].velocity.y * 0.6
});
Matter.Body.setPosition(this, Vector.add(this.position, q[i].velocity)) //move with the medium
let dmg = this.dmg / Math.min(10, q[i].mass)
@@ -743,9 +870,9 @@ const b = {
this.cycle++
const wiggleMag = (mech.crouch ? 6 : 12) * Math.cos(game.cycle * 0.09)
const wiggle = Vector.mult(transverse, wiggleMag * Math.cos(this.cycle * 0.36)) //+ wiggleMag * Math.cos(game.cycle * 0.3))
// const velocity = Vector.mult(player.velocity, 0.25) //move with player
// Matter.Body.setPosition(this, Vector.add(velocity, Vector.add(this.position, wiggle)))
Matter.Body.setPosition(this, Vector.add(this.position, wiggle))
const velocity = Vector.mult(player.velocity, 0.3) //move with player
Matter.Body.setPosition(this, Vector.add(velocity, Vector.add(this.position, wiggle)))
// Matter.Body.setPosition(this, Vector.add(this.position, wiggle))
}
}
});
@@ -2089,11 +2216,11 @@ const b = {
const DIST = Vector.magnitude(sub);
const unit = Vector.normalise(sub)
if (DIST < mod.isPlasmaRange * 450 && mech.energy > this.drainThreshold) {
mech.energy -= 0.0012;
if (mech.energy < 0) {
mech.fieldCDcycle = mech.cycle + 120;
mech.energy = 0;
}
mech.energy -= 0.005;
// if (mech.energy < 0) {
// mech.fieldCDcycle = mech.cycle + 120;
// mech.energy = 0;
// }
//calculate laser collision
let best;
let range = mod.isPlasmaRange * (120 + 300 * Math.sqrt(Math.random()))
@@ -2164,7 +2291,7 @@ const b = {
y: best.y
};
if (best.who.alive) {
const dmg = 0.8 * b.dmgScale; //********** SCALE DAMAGE HERE *********************
const dmg = 0.6 * b.dmgScale; //********** SCALE DAMAGE HERE *********************
best.who.damage(dmg);
best.who.locatePlayer();
//push mobs away
@@ -3612,13 +3739,13 @@ const b = {
y: mech.pos.y + 3000 * Math.sin(mech.angle)
}, dmg, 0, true);
for (let i = 1; i < len; i++) {
const history = mech.history[(mech.cycle - i * spacing) % 300]
const history = mech.history[(mech.cycle - i * spacing) % 600]
b.laser({
x: history.position.x + 20 * Math.cos(history.angle),
y: history.position.y + 20 * Math.sin(history.angle)
y: history.position.y + 20 * Math.sin(history.angle) - mech.yPosDifference
}, {
x: history.position.x + 3000 * Math.cos(history.angle),
y: history.position.y + 3000 * Math.sin(history.angle)
y: history.position.y + 3000 * Math.sin(history.angle) - mech.yPosDifference
}, dmg, 0, true);
}
ctx.stroke();
@@ -3642,130 +3769,38 @@ const b = {
},
},
],
pulse(energy, angle = mech.angle) {
let best;
let explosionRange = 1560 * energy
let range = 3000
const path = [{
x: mech.pos.x + 20 * Math.cos(angle),
y: mech.pos.y + 20 * Math.sin(angle)
},
{
x: mech.pos.x + range * Math.cos(angle),
y: mech.pos.y + range * Math.sin(angle)
}
];
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 = game.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 = game.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 && (!domain[i].mob || domain[i].alive)) {
best = {
x: results.x,
y: results.y,
dist2: dist2,
who: domain[i],
v1: vertices[0],
v2: vertices[len]
};
gunRewind: { //this gun is added with a mod
name: "CPT gun",
description: "use <strong class='color-f'>energy</strong> to <strong>rewind</strong> your <strong class='color-h'>health</strong>, <strong>velocity</strong>,<br> and <strong>position</strong> up to <strong>10</strong> seconds",
ammo: 0,
ammoPack: Infinity,
have: false,
isRewinding: false,
lastFireCycle: 0,
holdCount: 0,
fire() {
if (this.lastFireCycle === mech.cycle - 1) { //button has been held down
this.rewindCount += 7;
const DRAIN = 0.01
if (this.rewindCount > 599 || mech.energy < DRAIN) {
this.rewindCount = 0;
mech.resetHistory();
mech.fireCDcycle = mech.cycle + Math.floor(60 * b.fireCD); // cool down
} else {
mech.energy -= DRAIN
mech.immuneCycle = mech.cycle + 5; //player is immune to collision damage for 5 cycles
let history = mech.history[(mech.cycle - this.rewindCount) % 600]
Matter.Body.setPosition(player, history.position);
Matter.Body.setVelocity(player, { x: history.velocity.x, y: history.velocity.y });
if (mech.health !== history.health) {
mech.health = history.health
mech.displayHealth();
}
}
} else { //button is held the first time
this.rewindCount = 0;
}
};
//check for collisions
best = {
x: null,
y: null,
dist2: Infinity,
who: null,
v1: null,
v2: null
};
if (mod.isPulseAim) { //find mobs in line of sight
let dist = 2200
for (let i = 0, len = mob.length; i < len; i++) {
const newDist = Vector.magnitude(Vector.sub(path[0], mob[i].position))
if (explosionRange < newDist &&
newDist < dist &&
Matter.Query.ray(map, path[0], mob[i].position).length === 0 &&
Matter.Query.ray(body, path[0], mob[i].position).length === 0) {
dist = newDist
best.who = mob[i]
path[path.length - 1] = mob[i].position
}
}
}
if (!best.who) {
vertexCollision(path[0], path[1], mob);
vertexCollision(path[0], path[1], map);
vertexCollision(path[0], path[1], body);
if (best.dist2 != Infinity) { //if hitting something
path[path.length - 1] = {
x: best.x,
y: best.y
};
}
}
if (best.who) b.explosion(path[1], explosionRange, true)
if (mod.isPulseStun) {
const range = 100 + 2000 * energy
for (let i = 0, len = mob.length; i < len; ++i) {
if (mob[i].alive && !mob[i].isShielded) {
dist = Vector.magnitude(Vector.sub(path[1], mob[i].position)) - mob[i].radius;
if (dist < range) mobs.statusStun(mob[i], 30 + Math.floor(energy * 60))
}
}
}
//draw laser beam
ctx.beginPath();
ctx.moveTo(path[0].x, path[0].y);
ctx.lineTo(path[1].x, path[1].y);
ctx.strokeStyle = "rgba(255,0,0,0.13)"
ctx.lineWidth = 60 * energy / 0.2
ctx.stroke();
ctx.strokeStyle = "rgba(255,0,0,0.2)"
ctx.lineWidth = 18
ctx.stroke();
ctx.strokeStyle = "#f00";
ctx.lineWidth = 4
ctx.stroke();
//draw little dots along the laser path
const sub = Vector.sub(path[1], path[0])
const mag = Vector.magnitude(sub)
for (let i = 0, len = Math.floor(mag * 0.03 * energy / 0.2); i < len; i++) {
const dist = Math.random()
game.drawList.push({
x: path[0].x + sub.x * dist + 13 * (Math.random() - 0.5),
y: path[0].y + sub.y * dist + 13 * (Math.random() - 0.5),
radius: 1 + 4 * Math.random(),
color: "rgba(255,0,0,0.5)",
time: Math.floor(2 + 33 * Math.random() * Math.random())
});
this.lastFireCycle = mech.cycle;
}
}
};

View File

@@ -596,7 +596,17 @@ const game = {
}
if (mod.isEndLevelPowerUp) {
for (let i = 0; i < powerUp.length; i++) powerUp[i].effect();
for (let i = 0; i < powerUp.length; i++) {
if (powerUp[i].name === "mod") {
mod.giveMod()
} else if (powerUp[i].name === "gun") {
if (!mod.isOneGun) b.giveGuns("random")
} else if (powerUp[i].name === "field") {
if (mech.fieldMode === 0) mech.setField(Math.ceil(Math.random() * (mech.fieldUpgrades.length - 1))) //pick a random field, but not field 0
} else {
powerUp[i].effect();
}
}
}
powerUps.totalPowerUps = powerUp.length
@@ -761,24 +771,24 @@ const game = {
x: 0,
y: 40
});
if ((playerHead.position.y - player.position.y) > 0) {
Matter.Body.translate(playerHead, {
x: 0,
y: 40
});
if ((playerHead.position.y - player.position.y) > 0) {
Matter.Body.translate(playerHead, {
x: 0,
y: 40
});
if ((playerHead.position.y - player.position.y) > 0) {
Matter.Body.translate(playerHead, {
x: 0,
y: 40
});
}
}
}
// if ((playerHead.position.y - player.position.y) > 0) {
// Matter.Body.translate(playerHead, {
// x: 0,
// y: 40
// });
// if ((playerHead.position.y - player.position.y) > 0) {
// Matter.Body.translate(playerHead, {
// x: 0,
// y: 40
// });
// if ((playerHead.position.y - player.position.y) > 0) {
// Matter.Body.translate(playerHead, {
// x: 0,
// y: 40
// });
// }
// }
// }
} else if (mech.crouch && ((playerHead.position.y - player.position.y) > 10)) {
Matter.Body.translate(playerHead, {
x: 0,

View File

@@ -787,7 +787,7 @@ window.addEventListener("keydown", function(event) {
break
}
if (game.testing) {
switch (event.key) {
switch (event.key.toLowerCase()) {
case "o":
game.isAutoZoom = false;
game.zoomScale /= 0.9;
@@ -1081,4 +1081,24 @@ function cycle() {
// loop[i]()
// }
}
}
}
//display console logs in game
// function proxy(context, method, message) {
// return function() {
// // method.apply(context, [message].concat(Array.prototype.slice.apply(arguments)))
// game.makeTextLog(arguments[0], 300)
// }
// }
// console.log = proxy(console, console.log, 'n-gon: ')
// console.error = proxy(console, console.error, 'Error:')
// console.warn = proxy(console, console.warn, 'Warning:')
// let's test
// console.log('im from console.log', level, 2, 3);
// console.error('im from console.error', 1, 2, 3);
// console.warn('im from console.warn', 1, 2, 3);

View File

@@ -13,17 +13,15 @@ const level = {
start() {
if (level.levelsCleared === 0) { //this code only runs on the first level
// game.enableConstructMode() //used to build maps in testing mode
// level.difficultyIncrease(19)
// level.difficultyIncrease(1)
// game.zoomScale = 1000;
// game.setZoom();
// mech.setField("plasma torch")
// b.giveGuns("wave beam")
// mod.giveMod("micro-extruder")
// mod.giveMod("piezoelectricity")
// mod.giveMod("CPT reversal")
// mod.giveMod("CPT gun")
// for (let i = 0; i < 15; i++) mod.giveMod("plasma jet")
level.intro(); //starting level
// level.testing(); //not in rotation
// level.finalBoss() //final boss level
@@ -163,12 +161,12 @@ const level = {
// spawn.launcherBoss(1200, -500)
// spawn.laserTargetingBoss(1600, -400)
// spawn.striker(1600, -500)
spawn.shooter(1700, -120)
// spawn.shooter(1700, -120)
// spawn.bomberBoss(1400, -500)
// spawn.sniper(1800, -120)
// spawn.cellBossCulture(1600, -500)
// spawn.spiderBoss(1600, -500)
// spawn.laser(1200, -500)
spawn.streamBoss(1600, -500)
// spawn.beamer(1200, -500)
// spawn.shield(mob[mob.length - 1], 1800, -120, 1);
// spawn.nodeBoss(1200, -500, "launcher")
@@ -793,9 +791,9 @@ const level = {
powerUps.spawnBossPowerUp(-125, -1760);
} else {
if (Math.random() < 0.5) {
spawn.randomLevelBoss(700, -1550, ["shooterBoss", "launcherBoss", "laserTargetingBoss"]);
spawn.randomLevelBoss(700, -1550, ["shooterBoss", "launcherBoss", "laserTargetingBoss", "streamBoss"]);
} else {
spawn.randomLevelBoss(675, -2775, ["shooterBoss", "launcherBoss", "laserTargetingBoss"]);
spawn.randomLevelBoss(675, -2775, ["shooterBoss", "launcherBoss", "laserTargetingBoss", "streamBoss"]);
}
}
powerUps.addRerollToLevel() //needs to run after mobs are spawned
@@ -942,7 +940,7 @@ const level = {
spawn.randomMob(3600, 1725, 0.9);
spawn.randomMob(4100, 1225, 0.9);
spawn.randomMob(2825, 400, 0.9);
if (game.difficulty > 3) spawn.randomLevelBoss(6000, 2300, ["spiderBoss", "launcherBoss", "laserTargetingBoss"]);
if (game.difficulty > 3) spawn.randomLevelBoss(6000, 2300, ["spiderBoss", "launcherBoss", "laserTargetingBoss", "streamBoss"]);
powerUps.addRerollToLevel() //needs to run after mobs are spawned
},
satellite() {

View File

@@ -481,7 +481,7 @@ const mobs = {
}
}
};
if (this.seePlayer.recall) {
if (this.seePlayer.recall && !this.isSlowed) {
this.torque = this.lookTorque * this.inertia * 2;
const seeRange = 2500;

View File

@@ -386,22 +386,6 @@ const mod = {
mod.throwChargeRate = 1
}
},
{
name: "fragmentation",
description: "detonation or collisions with mobs eject <strong>nails</strong><br><em>blocks, rail gun, grenades, shotgun slugs</em>",
maxCount: 9,
count: 0,
allowed() {
return (mod.haveGunCheck("grenades") && !mod.isNeutronBomb) || mod.haveGunCheck("rail gun") || (mod.haveGunCheck("shotgun") && mod.isSlugShot) || mod.throwChargeRate > 1
},
requires: "grenades, rail gun, shotgun slugs, or mass driver",
effect() {
mod.fragments++
},
remove() {
mod.fragments = 0
}
},
{
name: "ammonium nitrate",
description: "increase <strong class='color-e'>explosive</strong> <strong class='color-d'>damage</strong> by <strong>20%</strong><br>increase <strong class='color-e'>explosive</strong> <strong>radius</strong> by <strong>20%</strong>",
@@ -569,7 +553,7 @@ const mod = {
b.nailBot();
},
remove() {
mod.nailBotCount = 0;
mod.nailBotCount -= this.count;
}
},
{
@@ -608,7 +592,7 @@ const mod = {
b.foamBot();
},
remove() {
mod.foamBotCount = 0;
mod.foamBotCount -= this.count;
}
},
{
@@ -647,7 +631,7 @@ const mod = {
b.boomBot();
},
remove() {
mod.boomBotCount = 0;
mod.boomBotCount -= this.count;
}
},
{
@@ -686,7 +670,7 @@ const mod = {
b.laserBot();
},
remove() {
mod.laserBotCount = 0;
mod.laserBotCount -= this.count;
}
},
{
@@ -725,7 +709,7 @@ const mod = {
mod.orbitBotCount++;
},
remove() {
mod.orbitBotCount = 0;
mod.orbitBotCount -= this.count;
}
},
{
@@ -1074,9 +1058,9 @@ const mod = {
maxCount: 1,
count: 0,
allowed() { //&& (mech.fieldUpgrades[mech.fieldMode].name !== "nano-scale manufacturing" || mech.maxEnergy > 1)
return mech.maxEnergy > 0.99 && mech.fieldUpgrades[mech.fieldMode].name !== "standing wave harmonics" && !mod.isEnergyHealth
return mech.maxEnergy > 0.99 && mech.fieldUpgrades[mech.fieldMode].name !== "standing wave harmonics" && !mod.isEnergyHealth && !mod.isRewindGun
},
requires: "standing wave, mass-energy, piezoelectricity, max energy reduction",
requires: "not standing wave, mass-energy, piezo, max energy reduction, CPT gun",
effect() {
mod.isRewindAvoidDeath = true;
},
@@ -1135,13 +1119,13 @@ const mod = {
},
{
name: "ground state",
description: "reduce <strong class='color-harm'>harm</strong> by <strong>66%</strong><br>you <strong>no longer</strong> passively regenerate <strong class='color-f'>energy</strong>",
description: "reduce <strong class='color-harm'>harm</strong> by <strong>60%</strong><br>you <strong>no longer</strong> passively regenerate <strong class='color-f'>energy</strong>",
maxCount: 1,
count: 0,
allowed() {
return mod.isPiezo && mod.energyRegen !== 0.004
return (mod.iceEnergy || mod.isWormholeEnergy || mod.isPiezo || mod.isRailEnergyGain) && mod.energyRegen !== 0.004
},
requires: "piezoelectricity, not time crystals",
requires: "piezoelectricity, Penrose, half-wave, or thermoelectric, but not time crystals",
effect: () => {
mod.energyRegen = 0;
mech.fieldRegen = mod.energyRegen;
@@ -1157,7 +1141,7 @@ const mod = {
maxCount: 1,
count: 0,
allowed() {
return !mod.isEnergyLoss && !mod.isPiezo && !mod.isRewindAvoidDeath && !mod.isSpeedHarm && mech.fieldUpgrades[mech.fieldMode].name !== "negative mass field"
return !mod.isEnergyLoss && !mod.isPiezo && !mod.isRewindAvoidDeath && !mod.isRewindGun && !mod.isSpeedHarm && mech.fieldUpgrades[mech.fieldMode].name !== "negative mass field"
},
requires: "not exothermic process, piezoelectricity, CPT, 1st law, negative mass",
effect: () => {
@@ -1328,13 +1312,13 @@ const mod = {
},
{
name: "transceiver chip",
description: "at the end of each <strong>level</strong><br>gain the full <strong>effect</strong> of unused <strong>power ups</strong>",
description: "unused <strong>power ups</strong> at the end of each <strong>level</strong><br>are still activated <em>(selections are random)</em>",
maxCount: 1,
count: 0,
allowed() {
return mod.isArmorFromPowerUps
},
requires: "crystallized armor",
requires: "inductive coupling",
effect() {
mod.isEndLevelPowerUp = true;
},
@@ -1535,7 +1519,7 @@ const mod = {
if (mod.mods[i].count > 0) have.push(i)
}
const choose = have[Math.floor(Math.random() * have.length)]
game.makeTextLog(`<div class='circle mod'></div> &nbsp; <strong>${mod.mods[choose].name}</strong> removed by reallocation`, 300)
game.makeTextLog(`<div class='circle mod'></div> &nbsp; <strong>${mod.mods[choose].name}</strong> removed by monte carlo experiment`, 300)
for (let i = 0; i < mod.mods[choose].count; i++) {
powerUps.spawn(mech.pos.x, mech.pos.y, "mod");
}
@@ -1935,10 +1919,50 @@ const mod = {
//**************************************************
//************************************************** gun
//************************************************** mods
//**************************************************
//**************************************************
{
name: "CPT gun",
description: "adds the <strong>CPT</strong> <strong class='color-g'>gun</strong> to your inventory<br>it <strong>rewinds</strong> your <strong class='color-h'>health</strong>, <strong>velocity</strong>, and <strong>position</strong>",
isGunMod: true,
maxCount: 1,
count: 0,
allowed() {
return (mod.totalBots() > 5 || mech.fieldUpgrades[mech.fieldMode].name === "nano-scale manufacturing" || mech.fieldUpgrades[mech.fieldMode].name === "plasma torch" || mech.fieldUpgrades[mech.fieldMode].name === "pilot wave") && !mod.isEnergyHealth && !mod.isRewindAvoidDeath
},
requires: "bots > 5, plasma torch, nano-scale, pilot wave, not mass-energy equivalence, CPT",
effect() {
mod.isRewindGun = true
b.guns.push(b.gunRewind)
b.giveGuns("CPT gun");
},
remove() {
if (mod.isRewindGun) {
for (let i = 0; i < b.guns.length; i++) {
if (b.guns[i].name === "CPT gun") {
for (let j = 0; j < b.inventory.length; j++) {
if (b.inventory[j] === i) {
b.inventory.splice(j, 1)
break
}
}
if (b.inventory.length) {
b.activeGun = b.inventory[0];
} else {
b.activeGun = null;
}
game.makeGunHUD();
b.guns.splice(i, 1) //also remove CPT gun from gun pool array
break
}
}
mod.isRewindGun = false
}
}
},
{
name: "incendiary ammunition",
description: "<strong>bullets</strong> are loaded with <strong class='color-e'>explosives</strong><br><em style = 'font-size: 90%'>nail gun, shotgun, super balls, drones</em>",
description: "some <strong>bullets</strong> are loaded with <strong class='color-e'>explosives</strong><br><em style = 'font-size: 90%'>nail gun, shotgun, super balls, drones</em>",
isGunMod: true,
maxCount: 1,
count: 0,
@@ -1953,9 +1977,26 @@ const mod = {
mod.isIncendiary = false;
}
},
{
name: "fragmentation",
description: "some <strong class='color-e'>detonations</strong> and collisions eject <strong>nails</strong><br><em style = 'font-size: 90%'>blocks, rail gun, grenades, missiles, shotgun slugs</em>",
isGunMod: true,
maxCount: 9,
count: 0,
allowed() {
return (mod.haveGunCheck("grenades") && !mod.isNeutronBomb) || mod.haveGunCheck("missiles") || mod.haveGunCheck("rail gun") || (mod.haveGunCheck("shotgun") && mod.isSlugShot) || mod.throwChargeRate > 1
},
requires: "grenades, missiles, rail gun, shotgun slugs, or mass driver",
effect() {
mod.fragments++
},
remove() {
mod.fragments = 0
}
},
{
name: "Lorentzian topology",
description: "<strong>bullets</strong> last <strong>30% longer</strong><br><em style = 'font-size: 83%'>drones, spores, missiles, foam, wave, ice IX, neutron</em>",
description: "some <strong>bullets</strong> last <strong>30% longer</strong><br><em style = 'font-size: 83%'>drones, spores, missiles, foam, wave, ice IX, neutron</em>",
isGunMod: true,
maxCount: 3,
count: 0,
@@ -2783,7 +2824,7 @@ const mod = {
},
{
name: "colloidal foam",
description: "increase <strong>foam</strong> <strong class='color-d'>damage</strong> by <strong>200%</strong><br><strong>foam</strong> dissipates <strong>40%</strong> faster",
description: "increase <strong>foam</strong> <strong class='color-d'>damage</strong> by <strong>366%</strong><br><strong>foam</strong> dissipates <strong>40%</strong> faster",
isGunMod: true,
maxCount: 1,
count: 0,
@@ -3259,8 +3300,8 @@ const mod = {
mod.giveMod("orbital-bot upgrade")
mod.setModToNonRefundable("orbital-bot upgrade")
for (let i = 0; i < 2; i++) {
b.orbitalBot()
mod.orbitalBotCount++;
b.orbitBot()
mod.orbitBotCount++;
}
})
//choose random function from the array and run it
@@ -3370,6 +3411,23 @@ const mod = {
mod.isFreezeMobs = false
}
},
// {
// name: "thermal reservoir",
// description: "increase your <strong class='color-plasma'>plasma</strong> <strong class='color-d'>damage</strong> by <strong>100%</strong><br><strong class='color-plasma'>plasma</strong> temporarily lowers health not <strong class='color-f'>energy</strong>",
// isFieldMod: true,
// maxCount: 1,
// count: 0,
// allowed() {
// return mech.fieldUpgrades[mech.fieldMode].name === "plasma torch" && !mod.isEnergyHealth
// },
// requires: "plasma torch, not mass-energy equivalence",
// effect() {
// mod.isPlasmaRange += 0.27;
// },
// remove() {
// mod.isPlasmaRange = 1;
// }
// },
{
name: "plasma jet",
description: "increase <strong class='color-plasma'>plasma</strong> <strong>torch's</strong> range by <strong>27%</strong>",
@@ -3874,5 +3932,7 @@ const mod = {
isRewindBot: null,
isRewindGrenade: null,
isExtruder: null,
isEndLevelPowerUp: null
isEndLevelPowerUp: null,
isRewindGun: null
}

View File

@@ -103,6 +103,7 @@ const mech = {
x: 0,
y: 0
},
yPosDifference: 24.285923217549026, //player.position.y - mech.pos.y
Sy: 0, //adds a smoothing effect to vertical only
Vx: 0,
Vy: 0,
@@ -135,11 +136,11 @@ const mech = {
transY: 0,
history: [], //tracks the last second of player position
resetHistory() {
for (let i = 0; i < 300; i++) { //reset history
for (let i = 0; i < 600; i++) { //reset history
mech.history[i] = {
position: {
x: mech.pos.x,
y: mech.pos.y,
x: player.position.x,
y: player.position.y,
},
velocity: {
x: player.velocity.x,
@@ -159,10 +160,10 @@ const mech = {
//tracks the last second of player information
// console.log(mech.history)
mech.history.splice(mech.cycle % 300, 1, {
mech.history.splice(mech.cycle % 600, 1, {
position: {
x: mech.pos.x,
y: mech.pos.y,
x: player.position.x,
y: player.position.y,
},
velocity: {
x: player.velocity.x,
@@ -461,14 +462,14 @@ const mech = {
if (mod.isBotArmor) dmg *= 0.97 ** mod.totalBots()
if (mod.isHarmArmor && mech.lastHarmCycle + 600 > mech.cycle) dmg *= 0.33;
if (mod.isNoFireDefense && mech.cycle > mech.fireCDcycle + 120) dmg *= 0.6
if (mod.energyRegen === 0) dmg *= 0.33 //0.22 + 0.78 * mech.energy //77% damage reduction at zero energy
if (mod.energyRegen === 0) dmg *= 0.4
if (mod.isTurret && mech.crouch) dmg *= 0.5;
if (mod.isEntanglement && b.inventory[0] === b.activeGun) {
for (let i = 0, len = b.inventory.length; i < len; i++) dmg *= 0.87 // 1 - 0.15
}
return dmg
},
rewind(steps) {
rewind(steps) { // mech.rewind(Math.floor(Math.min(599, 137 * mech.energy)))
if (mod.isRewindGrenade) {
for (let i = 1, len = Math.floor(2 + steps / 40); i < len; i++) {
b.grenade(Vector.add(mech.pos, { x: 10 * (Math.random() - 0.5), y: 10 * (Math.random() - 0.5) }), -i * Math.PI / len) //fire different angles for each grenade
@@ -494,7 +495,7 @@ const mech = {
}
}
}
let history = mech.history[(mech.cycle - steps) % 300]
let history = mech.history[(mech.cycle - steps) % 600]
Matter.Body.setPosition(player, history.position);
Matter.Body.setVelocity(player, { x: history.velocity.x, y: history.velocity.y });
// move bots to follow player
@@ -529,7 +530,7 @@ const mech = {
ctx.scale(game.zoom / game.edgeZoomOutSmooth, game.zoom / game.edgeZoomOutSmooth); //zoom in once centered
ctx.translate(-canvas.width2 + mech.transX, -canvas.height2 + mech.transY); //translate
for (let i = 1; i < steps; i++) {
history = mech.history[(mech.cycle - i) % 300]
history = mech.history[(mech.cycle - i) % 600]
mech.pos.x = history.position.x
mech.pos.y = history.position.y
mech.draw();
@@ -547,7 +548,7 @@ const mech = {
if (mod.isRewindBot) {
const len = steps * 0.042 * mod.isRewindBot
for (let i = 0; i < len; i++) {
const where = mech.history[Math.abs(mech.cycle - i * 40) % 300].position //spread out spawn locations along past history
const where = mech.history[Math.abs(mech.cycle - i * 40) % 600].position //spread out spawn locations along past history
b.randomBot({
x: where.x + 100 * (Math.random() - 0.5),
y: where.y + 100 * (Math.random() - 0.5)
@@ -558,8 +559,7 @@ const mech = {
},
damage(dmg) {
if (mod.isRewindAvoidDeath && mech.energy > 0.66) {
const steps = Math.floor(Math.min(299, 137 * mech.energy))
mech.rewind(steps)
mech.rewind(Math.floor(Math.min(299, 137 * mech.energy)))
return
}
mech.lastHarmCycle = mech.cycle
@@ -764,7 +764,7 @@ const mech = {
ctx.stroke();
// ctx.beginPath();
// ctx.arc(15, 0, 3, 0, 2 * Math.PI);
// ctx.fillStyle = '#9cf' //'#0cf';
// ctx.fillStyle = '#0cf';
// ctx.fill()
ctx.restore();
mech.yOff = mech.yOff * 0.85 + mech.yOffGoal * 0.15; //smoothly move leg height towards height goal
@@ -2194,11 +2194,104 @@ const mech = {
{
name: "wormhole",
description: "use <strong class='color-f'>energy</strong> to <strong>tunnel</strong> through a <strong class='color-worm'>wormhole</strong><br><strong class='color-worm'>wormholes</strong> attract blocks and power ups<br><strong>10%</strong> chance to <strong class='color-dup'>duplicate</strong> spawned <strong>power ups</strong>", //<br>bullets may also traverse <strong class='color-worm'>wormholes</strong>
effect: () => {
effect: function() {
game.replaceTextLog = true; //allow text over write
mech.drop();
mech.duplicateChance = 0.1
game.draw.powerUp = game.draw.powerUpBonus //change power up draw
// if (mod.isRewindGun) {
// mech.hold = this.rewind
// } else {
mech.hold = this.teleport
// }
},
rewindCount: 0,
// rewind: function() {
// if (input.down) {
// if (input.field && mech.fieldCDcycle < mech.cycle) { //not hold but field button is pressed
// const DRAIN = 0.01
// if (this.rewindCount < 289 && mech.energy > DRAIN) {
// mech.energy -= DRAIN
// if (this.rewindCount === 0) {
// const shortPause = function() {
// if (mech.defaultFPSCycle < mech.cycle) { //back to default values
// game.fpsCap = game.fpsCapDefault
// game.fpsInterval = 1000 / game.fpsCap;
// // document.getElementById("dmg").style.transition = "opacity 1s";
// // document.getElementById("dmg").style.opacity = "0";
// } else {
// requestAnimationFrame(shortPause);
// }
// };
// if (mech.defaultFPSCycle < mech.cycle) requestAnimationFrame(shortPause);
// game.fpsCap = 4 //1 is longest pause, 4 is standard
// game.fpsInterval = 1000 / game.fpsCap;
// mech.defaultFPSCycle = mech.cycle
// }
// this.rewindCount += 10;
// game.wipe = function() { //set wipe to have trails
// // ctx.fillStyle = "rgba(255,255,255,0)";
// ctx.fillStyle = `rgba(221,221,221,${0.004})`;
// ctx.fillRect(0, 0, canvas.width, canvas.height);
// }
// let history = mech.history[(mech.cycle - this.rewindCount) % 300]
// Matter.Body.setPosition(player, history.position);
// Matter.Body.setVelocity(player, { x: history.velocity.x, y: history.velocity.y });
// if (history.health > mech.health) {
// mech.health = history.health
// mech.displayHealth();
// }
// //grab power ups
// for (let i = 0, len = powerUp.length; i < len; ++i) {
// const dxP = player.position.x - powerUp[i].position.x;
// const dyP = player.position.y - powerUp[i].position.y;
// if (dxP * dxP + dyP * dyP < 50000 && !game.isChoosing && !(mech.health === mech.maxHealth && powerUp[i].name === "heal")) {
// powerUps.onPickUp(player.position);
// powerUp[i].effect();
// Matter.World.remove(engine.world, powerUp[i]);
// powerUp.splice(i, 1);
// const shortPause = function() {
// if (mech.defaultFPSCycle < mech.cycle) { //back to default values
// game.fpsCap = game.fpsCapDefault
// game.fpsInterval = 1000 / game.fpsCap;
// // document.getElementById("dmg").style.transition = "opacity 1s";
// // document.getElementById("dmg").style.opacity = "0";
// } else {
// requestAnimationFrame(shortPause);
// }
// };
// if (mech.defaultFPSCycle < mech.cycle) requestAnimationFrame(shortPause);
// game.fpsCap = 3 //1 is longest pause, 4 is standard
// game.fpsInterval = 1000 / game.fpsCap;
// mech.defaultFPSCycle = mech.cycle
// break; //because the array order is messed up after splice
// }
// }
// mech.immuneCycle = mech.cycle + 5; //player is immune to collision damage for 30 cycles
// } else {
// mech.fieldCDcycle = mech.cycle + 30;
// // mech.resetHistory();
// }
// } else {
// if (this.rewindCount !== 0) {
// mech.fieldCDcycle = mech.cycle + 30;
// mech.resetHistory();
// this.rewindCount = 0;
// game.wipe = function() { //set wipe to normal
// ctx.clearRect(0, 0, canvas.width, canvas.height);
// }
// }
// mech.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists)
// }
// }
// mech.drawFieldMeter()
// },
teleport: function() {
// mech.hole = { //this is reset with each new field, but I'm leaving it here for reference
// isOn: false,
// isReady: true,
@@ -2207,237 +2300,235 @@ const mech = {
// angle: 0,
// unit:{x:0,y:0},
// }
mech.hold = function() {
if (mech.hole.isOn) {
// draw holes
mech.fieldRange = 0.97 * mech.fieldRange + 0.03 * (50 + 10 * Math.sin(game.cycle * 0.025))
const semiMajorAxis = mech.fieldRange + 30
const edge1a = Vector.add(Vector.mult(mech.hole.unit, semiMajorAxis), mech.hole.pos1)
const edge1b = Vector.add(Vector.mult(mech.hole.unit, -semiMajorAxis), mech.hole.pos1)
const edge2a = Vector.add(Vector.mult(mech.hole.unit, semiMajorAxis), mech.hole.pos2)
const edge2b = Vector.add(Vector.mult(mech.hole.unit, -semiMajorAxis), mech.hole.pos2)
ctx.beginPath();
ctx.moveTo(edge1a.x, edge1a.y)
ctx.bezierCurveTo(mech.hole.pos1.x, mech.hole.pos1.y, mech.hole.pos2.x, mech.hole.pos2.y, edge2a.x, edge2a.y);
ctx.lineTo(edge2b.x, edge2b.y)
ctx.bezierCurveTo(mech.hole.pos2.x, mech.hole.pos2.y, mech.hole.pos1.x, mech.hole.pos1.y, edge1b.x, edge1b.y);
ctx.fillStyle = `rgba(255,255,255,${200 / mech.fieldRange / mech.fieldRange})` //"rgba(0,0,0,0.1)"
ctx.fill();
ctx.beginPath();
ctx.ellipse(mech.hole.pos1.x, mech.hole.pos1.y, mech.fieldRange, semiMajorAxis, mech.hole.angle, 0, 2 * Math.PI)
ctx.ellipse(mech.hole.pos2.x, mech.hole.pos2.y, mech.fieldRange, semiMajorAxis, mech.hole.angle, 0, 2 * Math.PI)
ctx.fillStyle = `rgba(255,255,255,${32 / mech.fieldRange})`
ctx.fill();
if (mech.hole.isOn) {
// draw holes
mech.fieldRange = 0.97 * mech.fieldRange + 0.03 * (50 + 10 * Math.sin(game.cycle * 0.025))
const semiMajorAxis = mech.fieldRange + 30
const edge1a = Vector.add(Vector.mult(mech.hole.unit, semiMajorAxis), mech.hole.pos1)
const edge1b = Vector.add(Vector.mult(mech.hole.unit, -semiMajorAxis), mech.hole.pos1)
const edge2a = Vector.add(Vector.mult(mech.hole.unit, semiMajorAxis), mech.hole.pos2)
const edge2b = Vector.add(Vector.mult(mech.hole.unit, -semiMajorAxis), mech.hole.pos2)
ctx.beginPath();
ctx.moveTo(edge1a.x, edge1a.y)
ctx.bezierCurveTo(mech.hole.pos1.x, mech.hole.pos1.y, mech.hole.pos2.x, mech.hole.pos2.y, edge2a.x, edge2a.y);
ctx.lineTo(edge2b.x, edge2b.y)
ctx.bezierCurveTo(mech.hole.pos2.x, mech.hole.pos2.y, mech.hole.pos1.x, mech.hole.pos1.y, edge1b.x, edge1b.y);
ctx.fillStyle = `rgba(255,255,255,${200 / mech.fieldRange / mech.fieldRange})` //"rgba(0,0,0,0.1)"
ctx.fill();
ctx.beginPath();
ctx.ellipse(mech.hole.pos1.x, mech.hole.pos1.y, mech.fieldRange, semiMajorAxis, mech.hole.angle, 0, 2 * Math.PI)
ctx.ellipse(mech.hole.pos2.x, mech.hole.pos2.y, mech.fieldRange, semiMajorAxis, mech.hole.angle, 0, 2 * Math.PI)
ctx.fillStyle = `rgba(255,255,255,${32 / mech.fieldRange})`
ctx.fill();
//suck power ups
for (let i = 0, len = powerUp.length; i < len; ++i) {
//which hole is closer
const dxP1 = mech.hole.pos1.x - powerUp[i].position.x;
const dyP1 = mech.hole.pos1.y - powerUp[i].position.y;
const dxP2 = mech.hole.pos2.x - powerUp[i].position.x;
const dyP2 = mech.hole.pos2.y - powerUp[i].position.y;
let dxP, dyP, dist2
if (dxP1 * dxP1 + dyP1 * dyP1 < dxP2 * dxP2 + dyP2 * dyP2) {
dxP = dxP1
dyP = dyP1
} else {
dxP = dxP2
dyP = dyP2
}
dist2 = dxP * dxP + dyP * dyP;
if (dist2 < 600000 && !(mech.health === mech.maxHealth && powerUp[i].name === "heal")) {
powerUp[i].force.x += 4 * (dxP / dist2) * powerUp[i].mass; // float towards hole
powerUp[i].force.y += 4 * (dyP / dist2) * powerUp[i].mass - powerUp[i].mass * game.g; //negate gravity
Matter.Body.setVelocity(powerUp[i], { //extra friction
x: powerUp[i].velocity.x * 0.05,
y: powerUp[i].velocity.y * 0.05
});
if (dist2 < 1000 && !game.isChoosing) { //use power up if it is close enough
mech.fieldRange *= 0.8
powerUps.onPickUp(powerUp[i].position);
powerUp[i].effect();
Matter.World.remove(engine.world, powerUp[i]);
powerUp.splice(i, 1);
break; //because the array order is messed up after splice
}
//suck power ups
for (let i = 0, len = powerUp.length; i < len; ++i) {
//which hole is closer
const dxP1 = mech.hole.pos1.x - powerUp[i].position.x;
const dyP1 = mech.hole.pos1.y - powerUp[i].position.y;
const dxP2 = mech.hole.pos2.x - powerUp[i].position.x;
const dyP2 = mech.hole.pos2.y - powerUp[i].position.y;
let dxP, dyP, dist2
if (dxP1 * dxP1 + dyP1 * dyP1 < dxP2 * dxP2 + dyP2 * dyP2) {
dxP = dxP1
dyP = dyP1
} else {
dxP = dxP2
dyP = dyP2
}
dist2 = dxP * dxP + dyP * dyP;
if (dist2 < 600000 && !(mech.health === mech.maxHealth && powerUp[i].name === "heal")) {
powerUp[i].force.x += 4 * (dxP / dist2) * powerUp[i].mass; // float towards hole
powerUp[i].force.y += 4 * (dyP / dist2) * powerUp[i].mass - powerUp[i].mass * game.g; //negate gravity
Matter.Body.setVelocity(powerUp[i], { //extra friction
x: powerUp[i].velocity.x * 0.05,
y: powerUp[i].velocity.y * 0.05
});
if (dist2 < 1000 && !game.isChoosing) { //use power up if it is close enough
mech.fieldRange *= 0.8
powerUps.onPickUp(powerUp[i].position);
powerUp[i].effect();
Matter.World.remove(engine.world, powerUp[i]);
powerUp.splice(i, 1);
break; //because the array order is messed up after splice
}
}
//suck and shrink blocks
const suckRange = 500
const shrinkRange = 100
const shrinkScale = 0.97;
const slowScale = 0.9
for (let i = 0, len = body.length; i < len; i++) {
if (!body[i].isNotHoldable) {
const dist1 = Vector.magnitude(Vector.sub(mech.hole.pos1, body[i].position))
const dist2 = Vector.magnitude(Vector.sub(mech.hole.pos2, body[i].position))
if (dist1 < dist2) {
if (dist1 < suckRange) {
const pull = Vector.mult(Vector.normalise(Vector.sub(mech.hole.pos1, body[i].position)), 1)
const slow = Vector.mult(body[i].velocity, slowScale)
Matter.Body.setVelocity(body[i], Vector.add(slow, pull));
//shrink
if (Vector.magnitude(Vector.sub(mech.hole.pos1, body[i].position)) < shrinkRange) {
Matter.Body.scale(body[i], shrinkScale, shrinkScale);
if (body[i].mass < 0.05) {
Matter.World.remove(engine.world, body[i]);
body.splice(i, 1);
mech.fieldRange *= 0.8
if (mod.isWormholeEnergy) mech.energy += 0.5
if (mod.isWormSpores) { //pandimensionalspermia
for (let i = 0, len = Math.ceil(3 * Math.random()); i < len; i++) {
b.spore(Vector.add(mech.hole.pos2, Vector.rotate({
x: mech.fieldRange * 0.4,
y: 0
}, 2 * Math.PI * Math.random())))
Matter.Body.setVelocity(bullet[bullet.length - 1], Vector.mult(Vector.rotate(mech.hole.unit, Math.PI / 2), -15));
}
}
break
}
}
}
} else if (dist2 < suckRange) {
const pull = Vector.mult(Vector.normalise(Vector.sub(mech.hole.pos2, body[i].position)), 1)
}
//suck and shrink blocks
const suckRange = 500
const shrinkRange = 100
const shrinkScale = 0.97;
const slowScale = 0.9
for (let i = 0, len = body.length; i < len; i++) {
if (!body[i].isNotHoldable) {
const dist1 = Vector.magnitude(Vector.sub(mech.hole.pos1, body[i].position))
const dist2 = Vector.magnitude(Vector.sub(mech.hole.pos2, body[i].position))
if (dist1 < dist2) {
if (dist1 < suckRange) {
const pull = Vector.mult(Vector.normalise(Vector.sub(mech.hole.pos1, body[i].position)), 1)
const slow = Vector.mult(body[i].velocity, slowScale)
Matter.Body.setVelocity(body[i], Vector.add(slow, pull));
//shrink
if (Vector.magnitude(Vector.sub(mech.hole.pos2, body[i].position)) < shrinkRange) {
if (Vector.magnitude(Vector.sub(mech.hole.pos1, body[i].position)) < shrinkRange) {
Matter.Body.scale(body[i], shrinkScale, shrinkScale);
if (body[i].mass < 0.05) {
Matter.World.remove(engine.world, body[i]);
body.splice(i, 1);
mech.fieldRange *= 0.8
// if (mod.isWormholeEnergy && mech.energy < mech.maxEnergy * 2) mech.energy = mech.maxEnergy * 2
if (mod.isWormholeEnergy) mech.energy += 0.5
if (mod.isWormSpores) { //pandimensionalspermia
for (let i = 0, len = Math.ceil(3 * Math.random()); i < len; i++) {
b.spore(Vector.add(mech.hole.pos1, Vector.rotate({
b.spore(Vector.add(mech.hole.pos2, Vector.rotate({
x: mech.fieldRange * 0.4,
y: 0
}, 2 * Math.PI * Math.random())))
Matter.Body.setVelocity(bullet[bullet.length - 1], Vector.mult(Vector.rotate(mech.hole.unit, Math.PI / 2), 15));
Matter.Body.setVelocity(bullet[bullet.length - 1], Vector.mult(Vector.rotate(mech.hole.unit, Math.PI / 2), -15));
}
}
break
}
}
}
}
}
if (mod.isWormBullets) {
//teleport bullets
for (let i = 0, len = bullet.length; i < len; ++i) { //teleport bullets from hole1 to hole2
if (!bullet[i].botType && !bullet[i].isInHole) { //don't teleport bots
if (Vector.magnitude(Vector.sub(mech.hole.pos1, bullet[i].position)) < mech.fieldRange) { //find if bullet is touching hole1
Matter.Body.setPosition(bullet[i], Vector.add(mech.hole.pos2, Vector.sub(mech.hole.pos1, bullet[i].position)));
mech.fieldRange += 5
bullet[i].isInHole = true
} else if (Vector.magnitude(Vector.sub(mech.hole.pos2, bullet[i].position)) < mech.fieldRange) { //find if bullet is touching hole1
Matter.Body.setPosition(bullet[i], Vector.add(mech.hole.pos1, Vector.sub(mech.hole.pos2, bullet[i].position)));
mech.fieldRange += 5
bullet[i].isInHole = true
} else if (dist2 < suckRange) {
const pull = Vector.mult(Vector.normalise(Vector.sub(mech.hole.pos2, body[i].position)), 1)
const slow = Vector.mult(body[i].velocity, slowScale)
Matter.Body.setVelocity(body[i], Vector.add(slow, pull));
//shrink
if (Vector.magnitude(Vector.sub(mech.hole.pos2, body[i].position)) < shrinkRange) {
Matter.Body.scale(body[i], shrinkScale, shrinkScale);
if (body[i].mass < 0.05) {
Matter.World.remove(engine.world, body[i]);
body.splice(i, 1);
mech.fieldRange *= 0.8
// if (mod.isWormholeEnergy && mech.energy < mech.maxEnergy * 2) mech.energy = mech.maxEnergy * 2
if (mod.isWormholeEnergy) mech.energy += 0.5
if (mod.isWormSpores) { //pandimensionalspermia
for (let i = 0, len = Math.ceil(3 * Math.random()); i < len; i++) {
b.spore(Vector.add(mech.hole.pos1, Vector.rotate({
x: mech.fieldRange * 0.4,
y: 0
}, 2 * Math.PI * Math.random())))
Matter.Body.setVelocity(bullet[bullet.length - 1], Vector.mult(Vector.rotate(mech.hole.unit, Math.PI / 2), 15));
}
}
break
}
}
}
// mobs get pushed away
for (let i = 0, len = mob.length; i < len; i++) {
if (Vector.magnitude(Vector.sub(mech.hole.pos1, mob[i].position)) < 200) {
const pull = Vector.mult(Vector.normalise(Vector.sub(mech.hole.pos1, mob[i].position)), -0.07)
Matter.Body.setVelocity(mob[i], Vector.add(mob[i].velocity, pull));
}
if (Vector.magnitude(Vector.sub(mech.hole.pos2, mob[i].position)) < 200) {
const pull = Vector.mult(Vector.normalise(Vector.sub(mech.hole.pos2, mob[i].position)), -0.07)
Matter.Body.setVelocity(mob[i], Vector.add(mob[i].velocity, pull));
}
}
}
}
if (mod.isWormBullets) {
//teleport bullets
for (let i = 0, len = bullet.length; i < len; ++i) { //teleport bullets from hole1 to hole2
if (!bullet[i].botType && !bullet[i].isInHole) { //don't teleport bots
if (Vector.magnitude(Vector.sub(mech.hole.pos1, bullet[i].position)) < mech.fieldRange) { //find if bullet is touching hole1
Matter.Body.setPosition(bullet[i], Vector.add(mech.hole.pos2, Vector.sub(mech.hole.pos1, bullet[i].position)));
mech.fieldRange += 5
bullet[i].isInHole = true
} else if (Vector.magnitude(Vector.sub(mech.hole.pos2, bullet[i].position)) < mech.fieldRange) { //find if bullet is touching hole1
Matter.Body.setPosition(bullet[i], Vector.add(mech.hole.pos1, Vector.sub(mech.hole.pos2, bullet[i].position)));
mech.fieldRange += 5
bullet[i].isInHole = true
}
}
}
// mobs get pushed away
for (let i = 0, len = mob.length; i < len; i++) {
if (Vector.magnitude(Vector.sub(mech.hole.pos1, mob[i].position)) < 200) {
const pull = Vector.mult(Vector.normalise(Vector.sub(mech.hole.pos1, mob[i].position)), -0.07)
Matter.Body.setVelocity(mob[i], Vector.add(mob[i].velocity, pull));
}
if (Vector.magnitude(Vector.sub(mech.hole.pos2, mob[i].position)) < 200) {
const pull = Vector.mult(Vector.normalise(Vector.sub(mech.hole.pos2, mob[i].position)), -0.07)
Matter.Body.setVelocity(mob[i], Vector.add(mob[i].velocity, pull));
}
}
}
}
if (input.field && mech.fieldCDcycle < mech.cycle) { //not hold but field button is pressed
const justPastMouse = Vector.add(Vector.mult(Vector.normalise(Vector.sub(game.mouseInGame, mech.pos)), 50), game.mouseInGame)
const scale = 60
// console.log(Matter.Query.region(map, bounds))
if (mech.hole.isReady &&
(
Matter.Query.region(map, {
min: {
x: game.mouseInGame.x - scale,
y: game.mouseInGame.y - scale
},
max: {
x: game.mouseInGame.x + scale,
y: game.mouseInGame.y + scale
}
}).length === 0 &&
Matter.Query.ray(map, mech.pos, justPastMouse).length === 0
// Matter.Query.ray(map, mech.pos, game.mouseInGame).length === 0 &&
// Matter.Query.ray(map, player.position, game.mouseInGame).length === 0 &&
// Matter.Query.ray(map, player.position, justPastMouse).length === 0
)
) {
const sub = Vector.sub(game.mouseInGame, mech.pos)
const mag = Vector.magnitude(sub)
const drain = 0.03 + 0.005 * Math.sqrt(mag)
if (mech.energy > drain && mag > 300) {
mech.energy -= drain
mech.hole.isReady = false;
mech.fieldRange = 0
Matter.Body.setPosition(player, game.mouseInGame);
mech.buttonCD_jump = 0 //this might fix a bug with jumping
const velocity = Vector.mult(Vector.normalise(sub), 18)
Matter.Body.setVelocity(player, {
x: velocity.x,
y: velocity.y - 4 //an extra vertical kick so the player hangs in place longer
});
mech.immuneCycle = mech.cycle + 15; //player is immune to collision damage
// move bots to follow player
for (let i = 0; i < bullet.length; i++) {
if (bullet[i].botType) {
Matter.Body.setPosition(bullet[i], Vector.add(player.position, {
x: 250 * (Math.random() - 0.5),
y: 250 * (Math.random() - 0.5)
}));
Matter.Body.setVelocity(bullet[i], {
x: 0,
y: 0
});
if (input.field && mech.fieldCDcycle < mech.cycle) { //not hold but field button is pressed
const justPastMouse = Vector.add(Vector.mult(Vector.normalise(Vector.sub(game.mouseInGame, mech.pos)), 50), game.mouseInGame)
const scale = 60
// console.log(Matter.Query.region(map, bounds))
if (mech.hole.isReady &&
(
Matter.Query.region(map, {
min: {
x: game.mouseInGame.x - scale,
y: game.mouseInGame.y - scale
},
max: {
x: game.mouseInGame.x + scale,
y: game.mouseInGame.y + scale
}
}).length === 0 &&
Matter.Query.ray(map, mech.pos, justPastMouse).length === 0
// Matter.Query.ray(map, mech.pos, game.mouseInGame).length === 0 &&
// Matter.Query.ray(map, player.position, game.mouseInGame).length === 0 &&
// Matter.Query.ray(map, player.position, justPastMouse).length === 0
)
) {
const sub = Vector.sub(game.mouseInGame, mech.pos)
const mag = Vector.magnitude(sub)
const drain = 0.03 + 0.005 * Math.sqrt(mag)
if (mech.energy > drain && mag > 300) {
mech.energy -= drain
mech.hole.isReady = false;
mech.fieldRange = 0
Matter.Body.setPosition(player, game.mouseInGame);
mech.buttonCD_jump = 0 //this might fix a bug with jumping
const velocity = Vector.mult(Vector.normalise(sub), 18)
Matter.Body.setVelocity(player, {
x: velocity.x,
y: velocity.y - 4 //an extra vertical kick so the player hangs in place longer
});
mech.immuneCycle = mech.cycle + 15; //player is immune to collision damage
// move bots to follow player
for (let i = 0; i < bullet.length; i++) {
if (bullet[i].botType) {
Matter.Body.setPosition(bullet[i], Vector.add(player.position, {
x: 250 * (Math.random() - 0.5),
y: 250 * (Math.random() - 0.5)
}));
Matter.Body.setVelocity(bullet[i], {
x: 0,
y: 0
});
}
}
//set holes
mech.hole.isOn = true;
mech.hole.pos1.x = mech.pos.x
mech.hole.pos1.y = mech.pos.y
mech.hole.pos2.x = player.position.x
mech.hole.pos2.y = player.position.y
mech.hole.angle = Math.atan2(sub.y, sub.x)
mech.hole.unit = Vector.perp(Vector.normalise(sub))
if (mod.isWormholeDamage) {
who = Matter.Query.ray(mob, mech.pos, game.mouseInGame, 80)
for (let i = 0; i < who.length; i++) {
if (who[i].body.alive) {
mobs.statusDoT(who[i].body, 0.6, 420)
mobs.statusStun(who[i].body, 240)
}
}
//set holes
mech.hole.isOn = true;
mech.hole.pos1.x = mech.pos.x
mech.hole.pos1.y = mech.pos.y
mech.hole.pos2.x = player.position.x
mech.hole.pos2.y = player.position.y
mech.hole.angle = Math.atan2(sub.y, sub.x)
mech.hole.unit = Vector.perp(Vector.normalise(sub))
if (mod.isWormholeDamage) {
who = Matter.Query.ray(mob, mech.pos, game.mouseInGame, 80)
for (let i = 0; i < who.length; i++) {
if (who[i].body.alive) {
mobs.statusDoT(who[i].body, 0.6, 420)
mobs.statusStun(who[i].body, 240)
}
}
}
} else {
mech.grabPowerUp();
}
} else {
mech.grabPowerUp();
}
} else if (mech.holdingTarget && mech.fieldCDcycle < mech.cycle) { //holding, but field button is released
mech.pickUp();
} else {
mech.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists)
mech.hole.isReady = true;
mech.grabPowerUp();
}
mech.drawFieldMeter()
} else if (mech.holdingTarget && mech.fieldCDcycle < mech.cycle) { //holding, but field button is released
mech.pickUp();
} else {
mech.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists)
mech.hole.isReady = true;
}
}
mech.drawFieldMeter()
},
},
],
};

View File

@@ -81,7 +81,7 @@ const spawn = {
}
}
},
randomLevelBoss(x, y, options = ["shooterBoss", "cellBossCulture", "bomberBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss", "powerUpBoss", "snakeBoss"]) {
randomLevelBoss(x, y, options = ["shooterBoss", "cellBossCulture", "bomberBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss", "powerUpBoss", "snakeBoss", "streamBoss"]) {
// other bosses: suckerBoss, laserBoss, tetherBoss, //all need a particular level to work so they are not included
spawn[options[Math.floor(Math.random() * options.length)]](x, y)
},
@@ -101,15 +101,34 @@ const spawn = {
level.bossKilled = true;
level.exit.x = 5500;
level.exit.y = -330;
//ramp up damage
for (let i = 0; i < 4; i++) level.difficultyIncrease(game.difficultyMode)
//pull in particles
for (let i = 0, len = body.length; i < len; ++i) { //push blocks away horizontally
for (let i = 0, len = body.length; i < len; ++i) {
const velocity = Vector.mult(Vector.normalise(Vector.sub(this.position, body[i].position)), 65)
const pushUp = Vector.add(velocity, { x: 0, y: -0.3 })
const pushUp = Vector.add(velocity, { x: 0, y: -0.5 })
Matter.Body.setVelocity(body[i], Vector.add(body[i].velocity, pushUp));
}
//ramp up damage
for (let i = 0; i < 5; i++) level.difficultyIncrease(game.difficultyMode)
//push away mobs
for (let i = 0, len = mob.length; i < len; ++i) {
if (mob[i] !== this) {
const velocity = Vector.mult(Vector.normalise(Vector.sub(this.position, mob[i].position)), -65)
Matter.Body.setVelocity(mob[i], Vector.add(mob[i].velocity, velocity));
}
}
//draw stuff
for (let i = 0, len = 22; i < len; i++) {
game.drawList.push({ //add dmg to draw queue
x: this.position.x,
y: this.position.y,
radius: (i + 1) * 150,
color: `rgba(255,255,255,0.17)`,
time: 5 * (len - i + 1)
});
}
};
me.onDamage = function() {};
@@ -761,7 +780,7 @@ const spawn = {
let me = mob[mob.length - 1];
me.stroke = "transparent"; //used for drawSneaker
me.eventHorizon = radius * 23; //required for blackhole
me.seeAtDistance2 = (me.eventHorizon + 300) * (me.eventHorizon + 300); //vision limit is event horizon
me.seeAtDistance2 = (me.eventHorizon + 400) * (me.eventHorizon + 400); //vision limit is event horizon
me.accelMag = 0.00009 * game.accelScale;
me.frictionAir = 0.025;
me.collisionFilter.mask = cat.player | cat.bullet
@@ -775,8 +794,15 @@ const spawn = {
y: this.velocity.y * 0.99
});
}
// this.seePlayerByDistOrLOS();
this.seePlayerCheckByDistance()
// this.seePlayerCheckByDistance()
if (!(game.cycle % this.seePlayerFreq)) {
if (this.distanceToPlayer2() < this.seeAtDistance2) { //&& !mech.isCloak ignore cloak for black holes
this.locatePlayer();
if (!this.seePlayer.yes) this.seePlayer.yes = true;
} else if (this.seePlayer.recall) {
this.lostPlayer();
}
}
this.checkStatus();
if (this.seePlayer.recall) {
//eventHorizon waves in and out
@@ -832,7 +858,7 @@ const spawn = {
me.isBoss = true;
me.stroke = "transparent"; //used for drawSneaker
me.eventHorizon = 1100; //required for black hole
me.seeAtDistance2 = (me.eventHorizon + 1000) * (me.eventHorizon + 1000); //vision limit is event horizon
me.seeAtDistance2 = (me.eventHorizon + 1200) * (me.eventHorizon + 1200); //vision limit is event horizon
me.accelMag = 0.00003 * game.accelScale;
me.collisionFilter.mask = cat.player | cat.bullet
// me.frictionAir = 0.005;
@@ -865,7 +891,14 @@ const spawn = {
y: this.velocity.y * 0.95
});
}
this.seePlayerByDistOrLOS();
if (!(game.cycle % this.seePlayerFreq)) {
if (this.distanceToPlayer2() < this.seeAtDistance2) { //&& !mech.isCloak ignore cloak for black holes
this.locatePlayer();
if (!this.seePlayer.yes) this.seePlayer.yes = true;
} else if (this.seePlayer.recall) {
this.lostPlayer();
}
}
this.checkStatus();
if (this.seePlayer.recall) {
//accelerate towards the player
@@ -1865,7 +1898,7 @@ const spawn = {
me.onHit = function() {
this.explode(this.mass * 20);
};
Matter.Body.setDensity(me, 0.00005); //normal is 0.001
Matter.Body.setDensity(me, 0.00004); //normal is 0.001
me.timeLeft = 200;
me.g = 0.001; //required if using 'gravity'
me.frictionAir = 0;
@@ -2106,7 +2139,7 @@ const spawn = {
me.frictionStatic = 0;
me.friction = 0;
me.frictionAir = 0.02;
me.memory = 420 * game.CDScale;
me.memory = 420;
me.repulsionRange = 1200000; //squared
spawn.shield(me, x, y, 1);
Matter.Body.setDensity(me, 0.004 + 0.0005 * Math.sqrt(game.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
@@ -2124,7 +2157,7 @@ const spawn = {
Matter.Body.setAngularVelocity(this, 0.11)
//fire a bullet from each vertex
for (let i = 0, len = this.vertices.length; i < len; i++) {
spawn.seeker(this.vertices[i].x, this.vertices[i].y, 7)
spawn.seeker(this.vertices[i].x, this.vertices[i].y, 6)
//give the bullet a rotational velocity as if they were attached to a vertex
const velocity = Vector.mult(Vector.perp(Vector.normalise(Vector.sub(this.position, this.vertices[i]))), -10)
Matter.Body.setVelocity(mob[mob.length - 1], {
@@ -2135,7 +2168,84 @@ const spawn = {
}
};
},
seeker(x, y, radius = 5, sides = 0) {
streamBoss(x, y, radius = 110) {
mobs.spawn(x, y, 5, radius, "rgb(245,180,255)");
let me = mob[mob.length - 1];
me.isBoss = true;
// me.accelMag = 0.00023 * game.accelScale;
me.accelMag = 0.00008 * game.accelScale;
// me.fireFreq = Math.floor(30 * game.CDScale)
me.canFire = false;
me.closestVertex1 = 0;
me.closestVertex2 = 1;
me.cycle = 0
me.frictionStatic = 0;
me.friction = 0;
me.frictionAir = 0.022;
me.memory = 240;
me.repulsionRange = 1200000; //squared
spawn.shield(me, x, y, 1);
Matter.Body.setDensity(me, 0.025); //extra dense //normal is 0.001 //makes effective life much larger
me.onDeath = function() {
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
// this.vertices = Matter.Vertices.hull(Matter.Vertices.clockwiseSort(this.vertices)) //helps collisions functions work better after vertex have been changed
};
me.onDamage = function() {};
me.do = function() {
this.seePlayerCheck();
this.checkStatus();
this.attraction();
this.repulsion();
this.cycle++
if (this.seePlayer.recall && ((this.cycle % 15) === 0) && !mech.isBodiesAsleep) {
if (this.canFire) {
if (this.cycle > 120) {
this.cycle = 0
this.canFire = false
// Matter.Body.setAngularVelocity(this, 0.1)
// const forceMag = 0.01 * this.mass;
// const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x);
// this.force.x -= 2 * forceMag * Math.cos(angle);
// this.force.y -= 2 * forceMag * Math.sin(angle); // - 0.0007 * this.mass; //antigravity
}
spawn.seeker(this.vertices[this.closestVertex1].x, this.vertices[this.closestVertex1].y, 4)
Matter.Body.setDensity(mob[mob.length - 1], 0.000001); //normal is 0.001
const velocity = Vector.mult(Vector.normalise(Vector.sub(this.position, this.vertices[this.closestVertex1])), -10)
Matter.Body.setVelocity(mob[mob.length - 1], {
x: this.velocity.x + velocity.x,
y: this.velocity.y + velocity.y
});
spawn.seeker(this.vertices[this.closestVertex2].x, this.vertices[this.closestVertex2].y, 4)
Matter.Body.setDensity(mob[mob.length - 1], 0.000001); //normal is 0.001
const velocity2 = Vector.mult(Vector.normalise(Vector.sub(this.position, this.vertices[this.closestVertex2])), -10)
Matter.Body.setVelocity(mob[mob.length - 1], {
x: this.velocity.x + velocity2.x,
y: this.velocity.y + velocity2.y
});
} else if (this.cycle > 210) {
this.cycle = 0
this.canFire = true
//find closest 2 vertexes
let distance2 = Infinity
for (let i = 0; i < this.vertices.length; i++) {
const d = Vector.magnitudeSquared(Vector.sub(this.vertices[i], player.position))
if (d < distance2) {
distance2 = d
this.closestVertex2 = this.closestVertex1
this.closestVertex1 = i
}
}
if (this.closestVertex2 === this.closestVertex1) {
this.closestVertex2++
if (this.closestVertex2 === this.vertices.length) this.closestVertex2 = 0
}
}
}
};
},
seeker(x, y, radius = 5, sides = 6) {
//bullets
mobs.spawn(x, y, sides, radius, "rgb(255,0,255)");
let me = mob[mob.length - 1];
@@ -2143,10 +2253,10 @@ const spawn = {
me.onHit = function() {
this.explode(this.mass * 20);
};
Matter.Body.setDensity(me, 0.00002); //normal is 0.001
Matter.Body.setDensity(me, 0.000015); //normal is 0.001
me.timeLeft = 420 * (0.8 + 0.4 * Math.random());
me.accelMag = 0.00017 * (0.8 + 0.4 * Math.random()) * game.accelScale;
me.frictionAir = 0.01 * (0.8 + 0.4 * Math.random());
me.accelMag = 0.00017 * game.accelScale; //* (0.8 + 0.4 * Math.random())
me.frictionAir = 0.01 //* (0.8 + 0.4 * Math.random());
me.restitution = 0.5;
me.leaveBody = false;
me.dropPowerUp = false;
@@ -2190,6 +2300,7 @@ const spawn = {
//run this function on hitting player
this.explode();
};
Matter.Body.setDensity(me, 0.0005); //normal is 0.001
me.g = 0.0001; //required if using 'gravity'
me.accelMag = 0.0003 * game.accelScale;
me.memory = 30;

View File

@@ -587,6 +587,7 @@ em {
/* background: rgb(116, 102, 238); */
/* background: hsl(253, 57%, 52%); */
background: hsl(255, 100%, 71%);
/* background: hsl(282, 100%, 64%); */
}
/* .grey {

View File

@@ -1,22 +1,16 @@
******************************************************** NEXT PATCH ********************************************************
your build url can now be copied in the pause screen
new level boss that fires 2 streams of small bullets that chase you
mod: inductive coupling - 4 max health per power up, but limited to 44 max health per level (replaces crystalized armor)
mod: transceiver chip - use all the power ups left over at the end of a level
mod: catabolism - does a flat 5 damage to your health for 3 ammo (was 2% of max health for 1 ammo)
mod: add a CPT gun to your inventory that rewinds your history, reverts your health, position, velocity for 10 seconds
I expect that spamming rewind has some overpowered combos.
Let me know what you find, and your ideas on balance.
******************************************************** BUGS ********************************************************
give worm hole pair production?
2nd mod for crystalized armor
no cap for health power ups?
(not able to reproduce, might be fixed) possible bug with neutron rewind
status doesn't apply correctly for spawned neutron bombs that are stuck to a shield
also saw neutron bombs bounce off shield, for normal bullets
test this more
check for crouch after rewind
CPT, tesseract
mod and mob are too similar
@@ -26,13 +20,15 @@ mod and mob are too similar
trigger a short term non-collide if that occurs
(12+ reports) bug - crouch and worm hole? -> crouch locked in
doesn't occur on my computer?
***try checking the date of the first bug, and then look at what patches came out right before that***
doesn't occur on my computer? but it does occur on fast computers
you can spoof it with mech.crouch = true in console
players have extra gravity
might be from the short jump code
add in a check every 7 seconds to try and fix it
this fix was added and it is working for some cases
maybe move the fix to once a second?
bug fix - rewrite crouch to not translate the player height, but instead switch between 2 sensors
(intermittent, but almost every time) bug - capping the fps causes random slow downs, that can be fixed with pause
@@ -44,7 +40,39 @@ mod and mob are too similar
******************************************************** TODO ********************************************************
make a reset hit box function as a way to fix crouch bug
mod: laser beams push like plasma torch pushes with directional force
mod: worm hole - you move through time instead of space. (field click to rewind)
add support for eating blocks, and damaging mobs that are nearby when you rewind
allow those mods
mod might not work as is because player needs to be able to pick up and move blocks sometimes
what about as a gun that uses energy not bullets?
mechanic: technological dead end - add mods to the mod pool with a dumb effect
don't show up in custom?
negative effect (one time effects are better to avoid code clutter)
make the player rainbow colors
mech.color = {
hue: 0,
sat: 100,
light: 50
}
setInterval(function(){
mech.color.hue++
mech.setFillColors()
}, 10);
remove all your energy
eject all your rerolls (not bad with dup)
teleport to the start of the level
remove your bots (requires you to have some bots)
your bots are changed to random bots
Mod: "High Risk": Spawn two bosses per level.
maybe limit to just the power up boss and spawn it at the exit every time to keep it simple
also weaken the player
remove a mod up?
lower harm reduction?
increase game difficulty by one level
mod that requires integrated armament
@@ -75,15 +103,6 @@ make different move methods
mod: when mobs are at full health you do 40% to them
mechanic: failed technology - add mods to the mod pool with a dumb effect
don't show up in custom?
negative effect (one time effects are better to avoid code clutter)
remove all your energy
eject all your rerolls (not bad with dup)
teleport to the start of the level
remove your bots (requires you to have some bots)
your bots are changed to random bots
mod - move super fast, go intangible, drain energy very fast
this is like a dodge roll
mod for standing wave?, cloaking?
@@ -371,12 +390,16 @@ robot AI communication
output to
bottom left message
tab title?
style
style
output console.log?
make it look like a computer terminal
track multiple lines, like your vocoder program
messages about heal, ammo, mods, that just list internal computer code
example: a heal would be mech.health += 12
mono space font
square edges
in baby talk?
with random ASCII gibberish letters
black text on bottom right with no background?
or white text, or yellow
end each message with a hexadecimal encryption code/hash
message after selecting each new (mod / gun / field)
put messages in (mod / gun / field) method
@@ -385,6 +408,14 @@ robot AI communication
you'd have to store an array of guns/fields/mod used last game
n-gon escape simulation ${random seed}
say something about what mobs types are queued up, and level order
**all communication should be from scientists watching the simulation; the robot shouldn't talk**
talking about the robot, watching
trying to communicate with the robot? but how
lines:
I think it's planing to escape
Why is it attacking those shapes?
Are those shapes supposed to be us?
add an ending to the game
maybe the game ending should ask you to open the console and type in some commands like in the end of doki doki