diff --git a/.DS_Store b/.DS_Store
index 4cb7f5b..039b8fb 100644
Binary files a/.DS_Store and b/.DS_Store differ
diff --git a/js/bullet.js b/js/bullet.js
index bd80b96..5b978e2 100644
--- a/js/bullet.js
+++ b/js/bullet.js
@@ -326,11 +326,12 @@ const b = {
//player damage
if (Vector.magnitude(Vector.sub(where, player.position)) < radius) {
- const drain = (tech.isExplosionHarm ? 0.5 : 0.25) * (tech.isImmuneExplosion ? Math.min(1, Math.max(1 - m.energy * 0.7, 0)) : 1)
- m.energy -= drain
+ const DRAIN = (tech.isExplosionHarm ? 0.5 : 0.25) * (tech.isRadioactiveResistance ? 0.25 : 1)
+ // * (tech.isImmuneExplosion ? Math.min(1, Math.max(1 - m.energy * 0.7, 0)) : 1)
+ m.energy -= DRAIN
if (m.energy < 0) {
m.energy = 0
- m.damage(0.03);
+ m.damage(0.03 * (tech.isRadioactiveResistance ? 0.25 : 1));
}
}
@@ -922,11 +923,10 @@ const b = {
bullet[me].restitution = 0;
bullet[me].minDmgSpeed = 0;
bullet[me].damageRadius = 100;
- bullet[me].maxDamageRadius = 450 + 130 * tech.isNeutronSlow + 130 * tech.isNeutronImmune //+ 150 * Math.random()
- bullet[me].radiusDecay = (0.81 + 0.15 * tech.isNeutronSlow + 0.15 * tech.isNeutronImmune) / tech.isBulletsLastLonger
+ bullet[me].maxDamageRadius = 450 + 130 * tech.isNeutronSlow //+ 150 * Math.random()
+ bullet[me].radiusDecay = (0.81 + 0.15 * tech.isNeutronSlow) / tech.isBulletsLastLonger
bullet[me].stuckTo = null;
bullet[me].stuckToRelativePosition = null;
- bullet[me].vacuumSlow = 0.97;
if (tech.isRPG) {
const SCALE = 2
@@ -1030,27 +1030,27 @@ const b = {
this.endCycle = 0;
} else {
//aoe damage to player
- if (!tech.isNeutronImmune && Vector.magnitude(Vector.sub(player.position, this.position)) < this.damageRadius) {
- const DRAIN = 0.0023
+ if (Vector.magnitude(Vector.sub(player.position, this.position)) < this.damageRadius) {
+ const DRAIN = tech.isRadioactiveResistance ? 0.0025 * 0.25 : 0.0025
if (m.energy > DRAIN) {
m.energy -= DRAIN
} else {
m.energy = 0;
- m.damage(0.00015)
+ m.damage(tech.isRadioactiveResistance ? 0.00016 * 0.25 : 0.00016) //0.00015
}
}
//aoe damage to mobs
for (let i = 0, len = mob.length; i < len; i++) {
if (Vector.magnitude(Vector.sub(mob[i].position, this.position)) < this.damageRadius) {
- let dmg = b.dmgScale * 0.082
+ let dmg = b.dmgScale * 0.09
if (Matter.Query.ray(map, mob[i].position, this.position).length > 0) dmg *= 0.25 //reduce damage if a wall is in the way
if (mob[i].shield) dmg *= 4 //x5 to make up for the /5 that shields normally take
mob[i].damage(dmg);
mob[i].locatePlayer();
if (tech.isNeutronSlow) {
Matter.Body.setVelocity(mob[i], {
- x: mob[i].velocity.x * this.vacuumSlow,
- y: mob[i].velocity.y * this.vacuumSlow
+ x: mob[i].velocity.x * 0.97,
+ y: mob[i].velocity.y * 0.97
});
}
}
@@ -1062,22 +1062,21 @@ const b = {
ctx.fill();
ctx.globalCompositeOperation = "source-over"
if (tech.isNeutronSlow) {
- const that = this
- function slow(who, radius = that.explodeRad * 3.2) {
+ let slow = (who, radius = this.explodeRad * 3.2) => {
for (i = 0, len = who.length; i < len; i++) {
- const sub = Vector.sub(that.position, who[i].position);
+ const sub = Vector.sub(this.position, who[i].position);
const dist = Vector.magnitude(sub);
if (dist < radius) {
Matter.Body.setVelocity(who[i], {
- x: who[i].velocity.x * that.vacuumSlow,
- y: who[i].velocity.y * that.vacuumSlow
+ x: who[i].velocity.x * 0.975,
+ y: who[i].velocity.y * 0.975
});
}
}
}
slow(body, this.damageRadius)
- if (!tech.isNeutronImmune) slow([player], this.damageRadius)
+ slow([player], this.damageRadius)
}
}
}
@@ -2210,6 +2209,242 @@ const b = {
y: speed * Math.sin(dir)
});
},
+ droneRadioactive(where = { x: m.pos.x + 30 * Math.cos(m.angle) + 20 * (Math.random() - 0.5), y: m.pos.y + 30 * Math.sin(m.angle) + 20 * (Math.random() - 0.5) }, speed = 1) {
+ const me = bullet.length;
+ const THRUST = tech.isFastDrones ? 0.002 : 0.0012
+ const dir = m.angle + 0.4 * (Math.random() - 0.5);
+ const RADIUS = (4 + 1 * Math.random())
+ bullet[me] = Bodies.polygon(where.x, where.y, 8, RADIUS, {
+ angle: dir,
+ inertia: Infinity,
+ friction: 0.05,
+ frictionAir: 0,
+ restitution: 1,
+ dmg: 0.24, //damage done in addition to the damage from momentum
+ lookFrequency: 120 + Math.floor(23 * Math.random()),
+ endCycle: simulation.cycle + Math.floor((900 + 400 * Math.random()) * tech.isBulletsLastLonger) + 140 + RADIUS * 5,
+ classType: "bullet",
+ collisionFilter: {
+ category: cat.bullet,
+ mask: cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet | cat.mobShield //self collide
+ },
+ minDmgSpeed: 0,
+ lockedOn: null,
+ isFollowMouse: true,
+ deathCycles: 110 + RADIUS * 5,
+ isImproved: false,
+ radioRadius: 0,
+ maxRadioRadius: 400 + Math.floor(75 * Math.random()) + 80 * tech.isNeutronSlow,
+ beforeDmg(who) {
+ const unit = Vector.mult(Vector.normalise(Vector.sub(this.position, who.position)), -20) //move away from target after hitting
+ Matter.Body.setVelocity(this, {
+ x: unit.x,
+ y: unit.y
+ });
+ this.lockedOn = null
+ if (this.endCycle > simulation.cycle + this.deathCycles) {
+ this.endCycle -= 60
+ if (simulation.cycle + this.deathCycles > this.endCycle) this.endCycle = simulation.cycle + this.deathCycles
+ }
+ },
+ onEnd() {
+ if (tech.isDroneRespawn) {
+ const who = b.guns[b.activeGun]
+ if (who.name === "drones" && who.ammo > 0 && mob.length) {
+ b.droneRadioactive({ x: this.position.x, y: this.position.y }, 0)
+ if (Math.random() < 0.33) {
+ b.guns[b.activeGun].ammo--;
+ simulation.updateGunHUD();
+ }
+ }
+ }
+ },
+ do() {
+ //radioactive zone
+ this.radioRadius = this.radioRadius * 0.993 + 0.007 * this.maxRadioRadius //smooth radius towards max
+ //aoe damage to player
+ if (Vector.magnitude(Vector.sub(player.position, this.position)) < this.radioRadius) {
+ const DRAIN = tech.isRadioactiveResistance ? 0.0023 * 0.25 : 0.0023
+ if (m.energy > DRAIN) {
+ m.energy -= DRAIN
+ } else {
+ m.energy = 0;
+ m.damage(tech.isRadioactiveResistance ? 0.00015 * 0.25 : 0.00015) //0.00015
+ }
+ }
+ //aoe damage to mobs
+ for (let i = 0, len = mob.length; i < len; i++) {
+ if (Vector.magnitude(Vector.sub(mob[i].position, this.position)) < this.radioRadius) {
+ let dmg = b.dmgScale * 0.035 //neutron bombs dmg = 0.09
+ if (Matter.Query.ray(map, mob[i].position, this.position).length > 0) dmg *= 0.25 //reduce damage if a wall is in the way
+ if (mob[i].shield) dmg *= 4 //x5 to make up for the /5 that shields normally take
+ mob[i].damage(dmg);
+ mob[i].locatePlayer();
+ if (tech.isNeutronSlow) {
+ Matter.Body.setVelocity(mob[i], {
+ x: mob[i].velocity.x * 0.97,
+ y: mob[i].velocity.y * 0.97
+ });
+ }
+ }
+ }
+ //draw
+ ctx.beginPath();
+ ctx.arc(this.position.x, this.position.y, this.radioRadius, 0, 2 * Math.PI);
+ ctx.globalCompositeOperation = "lighter"
+ ctx.fillStyle = `rgba(25,139,170,${0.1+0.05*Math.random()})`;
+ ctx.fill();
+ ctx.globalCompositeOperation = "source-over"
+
+ if (tech.isNeutronSlow) {
+ const slow = (who, radius = this.radioRadius * 3.2) => {
+ for (i = 0, len = who.length; i < len; i++) {
+ const sub = Vector.sub(this.position, who[i].position);
+ const dist = Vector.magnitude(sub);
+ if (dist < radius) {
+ Matter.Body.setVelocity(who[i], {
+ x: who[i].velocity.x * 0.975,
+ y: who[i].velocity.y * 0.975
+ });
+ }
+ }
+ }
+ slow(body, this.radioRadius)
+ slow([player], this.radioRadius)
+ }
+
+
+ //normal drone actions
+ if (simulation.cycle + this.deathCycles > this.endCycle) { //fall shrink and die
+ this.force.y += this.mass * 0.0012;
+ this.restitution = 0.2;
+ const scale = 0.995;
+ Matter.Body.scale(this, scale, scale);
+ this.maxRadioRadius = 0
+ this.radioRadius = this.radioRadius * 0.98 //let radioactivity decrease
+ } else {
+ this.force.y += this.mass * 0.0002; //gravity
+
+ if (!(simulation.cycle % this.lookFrequency)) {
+ //find mob targets
+ this.lockedOn = null;
+ let closeDist = Infinity;
+ for (let i = 0, len = mob.length; i < len; ++i) {
+ if (
+ !mob[i].isBadTarget &&
+ Matter.Query.ray(map, this.position, mob[i].position).length === 0 &&
+ Matter.Query.ray(body, this.position, mob[i].position).length === 0
+ ) {
+ const TARGET_VECTOR = Vector.sub(this.position, mob[i].position)
+ const DIST = Vector.magnitude(TARGET_VECTOR);
+ if (DIST < closeDist) {
+ closeDist = DIST;
+ this.lockedOn = mob[i]
+ }
+ }
+ }
+ //power ups
+ if (!this.isImproved && !simulation.isChoosing && !tech.isExtraMaxEnergy) {
+ if (this.lockedOn) {
+ //grab, but don't lock onto nearby power up
+ for (let i = 0, len = powerUp.length; i < len; ++i) {
+ if (
+ (powerUp[i].name !== "heal" || m.health < 0.9 * m.maxHealth || tech.isDroneGrab) &&
+ (powerUp[i].name !== "field" || !tech.isDeterminism) &&
+ Vector.magnitudeSquared(Vector.sub(this.position, powerUp[i].position)) < 20000
+ ) {
+ //draw pickup for a single cycle
+ ctx.beginPath();
+ ctx.moveTo(this.position.x, this.position.y);
+ ctx.lineTo(powerUp[i].position.x, powerUp[i].position.y);
+ ctx.strokeStyle = "#000"
+ ctx.lineWidth = 4
+ ctx.stroke();
+ //pick up nearby power ups
+ powerUps.onPickUp(powerUp[i]);
+ powerUp[i].effect();
+ Matter.World.remove(engine.world, powerUp[i]);
+ powerUp.splice(i, 1);
+ if (tech.isDroneGrab) {
+ this.isImproved = true;
+ const SCALE = 2.25
+ Matter.Body.scale(this, SCALE, SCALE);
+ this.lookFrequency = 30 + Math.floor(11 * Math.random());
+ this.endCycle += 1000 * tech.isBulletsLastLonger
+ this.maxRadioRadius *= 1.25
+ }
+ break;
+ }
+ }
+ } else {
+ //look for power ups to lock onto
+ let closeDist = Infinity;
+ for (let i = 0, len = powerUp.length; i < len; ++i) {
+ if (
+ (powerUp[i].name !== "heal" || m.health < 0.9 * m.maxHealth || tech.isDroneGrab) &&
+ (powerUp[i].name !== "field" || !tech.isDeterminism)
+ ) {
+ if (Vector.magnitudeSquared(Vector.sub(this.position, powerUp[i].position)) < 20000 && !simulation.isChoosing) {
+ //draw pickup for a single cycle
+ ctx.beginPath();
+ ctx.moveTo(this.position.x, this.position.y);
+ ctx.lineTo(powerUp[i].position.x, powerUp[i].position.y);
+ ctx.strokeStyle = "#000"
+ ctx.lineWidth = 4
+ ctx.stroke();
+ //pick up nearby power ups
+ powerUps.onPickUp(powerUp[i]);
+ powerUp[i].effect();
+ Matter.World.remove(engine.world, powerUp[i]);
+ powerUp.splice(i, 1);
+ if (tech.isDroneGrab) {
+ this.isImproved = true;
+ const SCALE = 2.25
+ Matter.Body.scale(this, SCALE, SCALE);
+ this.lookFrequency = 30 + Math.floor(11 * Math.random());
+ this.endCycle += 1000 * tech.isBulletsLastLonger
+ this.maxRadioRadius *= 1.25
+ }
+ break;
+ }
+ //look for power ups to lock onto
+ if (
+ Matter.Query.ray(map, this.position, powerUp[i].position).length === 0 &&
+ Matter.Query.ray(body, this.position, powerUp[i].position).length === 0
+ ) {
+ const TARGET_VECTOR = Vector.sub(this.position, powerUp[i].position)
+ const DIST = Vector.magnitude(TARGET_VECTOR);
+ if (DIST < closeDist) {
+ closeDist = DIST;
+ this.lockedOn = powerUp[i]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if (this.lockedOn) { //accelerate towards mobs
+ this.force = Vector.mult(Vector.normalise(Vector.sub(this.position, this.lockedOn.position)), -this.mass * THRUST)
+ } else { //accelerate towards mouse
+ this.force = Vector.mult(Vector.normalise(Vector.sub(this.position, simulation.mouseInGame)), -this.mass * THRUST)
+ }
+ // speed cap instead of friction to give more agility
+ if (this.speed > 6) {
+ Matter.Body.setVelocity(this, {
+ x: this.velocity.x * 0.97,
+ y: this.velocity.y * 0.97
+ });
+ }
+ }
+ }
+ })
+ World.add(engine.world, bullet[me]); //add bullet to world
+ Matter.Body.setVelocity(bullet[me], {
+ x: speed * Math.cos(dir),
+ y: speed * Math.sin(dir)
+ });
+ },
foam(position, velocity, radius) {
// radius *= Math.sqrt(tech.bulletSize)
const me = bullet.length;
@@ -3323,7 +3558,7 @@ const b = {
if (tech.isNailRadiation) {
mobs.statusDoT(who, tech.isFastRadiation ? 12 : 3, tech.isSlowRadiation ? 240 : (tech.isFastRadiation ? 30 : 120)) // one tick every 30 cycles
} else {
- let dmg = b.dmgScale * 5
+ let dmg = b.dmgScale * 5.5
if (tech.isCrit && who.isStunned) dmg *= 4
who.damage(dmg, tech.isNeedleShieldPierce);
simulation.drawList.push({ //add dmg to draw queue
@@ -3356,18 +3591,18 @@ const b = {
x: m.Vx / 2 + SPEED * Math.cos(angle),
y: m.Vy / 2 + SPEED * Math.sin(angle)
});
- Matter.Body.setDensity(bullet[me], 0.00001);
+ // Matter.Body.setDensity(bullet[me], 0.00001);
World.add(engine.world, bullet[me]); //add bullet to world
}
if (m.crouch) {
- m.fireCDcycle = m.cycle + 50 * b.fireCD; // cool down
+ m.fireCDcycle = m.cycle + 45 * b.fireCD; // cool down
makeNeedle()
for (let i = 1; i < 4; i++) { //4 total needles
setTimeout(() => { if (!simulation.paused) makeNeedle() }, 60 * i);
}
} else {
- m.fireCDcycle = m.cycle + 30 * b.fireCD; // cool down
+ m.fireCDcycle = m.cycle + 25 * b.fireCD; // cool down
makeNeedle()
for (let i = 1; i < 3; i++) { //3 total needles
setTimeout(() => { if (!simulation.paused) makeNeedle() }, 60 * i);
@@ -4145,12 +4380,22 @@ const b = {
have: false,
do() {},
fire() {
- if (m.crouch) {
- b.drone({ x: m.pos.x + 30 * Math.cos(m.angle) + 10 * (Math.random() - 0.5), y: m.pos.y + 30 * Math.sin(m.angle) + 10 * (Math.random() - 0.5) }, 45)
- m.fireCDcycle = m.cycle + Math.floor(13 * b.fireCD); // cool down
+ if (tech.isDroneRadioactive) {
+ if (m.crouch) {
+ b.droneRadioactive({ x: m.pos.x + 30 * Math.cos(m.angle) + 10 * (Math.random() - 0.5), y: m.pos.y + 30 * Math.sin(m.angle) + 10 * (Math.random() - 0.5) }, 45)
+ m.fireCDcycle = m.cycle + Math.floor(7 * 13 * b.fireCD); // cool down
+ } else {
+ b.droneRadioactive({ 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) }, 10)
+ m.fireCDcycle = m.cycle + Math.floor(7 * 6 * b.fireCD); // cool down
+ }
} else {
- b.drone()
- m.fireCDcycle = m.cycle + Math.floor(6 * b.fireCD); // cool down
+ if (m.crouch) {
+ b.drone({ x: m.pos.x + 30 * Math.cos(m.angle) + 10 * (Math.random() - 0.5), y: m.pos.y + 30 * Math.sin(m.angle) + 10 * (Math.random() - 0.5) }, 45)
+ m.fireCDcycle = m.cycle + Math.floor(13 * b.fireCD); // cool down
+ } else {
+ b.drone()
+ m.fireCDcycle = m.cycle + Math.floor(6 * b.fireCD); // cool down
+ }
}
}
},
diff --git a/js/level.js b/js/level.js
index 1e16ceb..768f834 100644
--- a/js/level.js
+++ b/js/level.js
@@ -16,12 +16,15 @@ const level = {
// simulation.difficulty = 20
// simulation.isHorizontalFlipped = true
// level.difficultyIncrease(99)
- // m.setField("standing wave harmonics")
- // tech.giveTech("spherical harmonics")
- // for (let i = 0; i < 9; i++) tech.giveTech("spherical harmonics")
+ // m.setField("nano-scale manufacturing")
// b.giveGuns("grenades")
+ // tech.giveTech("neutron bomb")
+ // b.giveGuns("drones")
+ // tech.giveTech("radioactive drones")
+ // tech.isRadioactiveResistance = true
+ // for (let i = 0; i < 9; i++) tech.giveTech("spherical harmonics")
// tech.isExplodeRadio = true
- // tech.giveTech("chain reaction")
+ // tech.giveTech("vacuum permittivity")
// tech.giveTech("quenching")
// tech.giveTech("decoherence")
// tech.giveTech("supertemporal")
@@ -96,7 +99,7 @@ const level = {
powerUps.spawn(player.position.x + Math.random() * 50, player.position.y - Math.random() * 50, "tech", false);
}
if (tech.isHealLowHealth) {
- const len = Math.ceil((m.maxHealth - m.health) / 0.33)
+ const len = Math.ceil((m.maxHealth - m.health) / 0.25)
for (let i = 0; i < len; i++) powerUps.spawn(player.position.x + 90 * (Math.random() - 0.5), player.position.y + 90 * (Math.random() - 0.5), "heal", false);
}
if (tech.isMACHO) spawn.MACHO()
@@ -965,23 +968,12 @@ const level = {
ctx.fillRect(this.min.x, this.min.y + offset, this.width, this.height - offset)
if (this.height > 0 && Matter.Query.region([player], this).length) {
- const drain = 0.003 + m.fieldRegen
- if (m.energy > drain) {
- m.energy -= drain
+ const DRAIN = 0.003 * (tech.isRadioactiveResistance ? 0.25 : 1) + m.fieldRegen
+ console.log(DRAIN)
+ if (m.energy > DRAIN) {
+ m.energy -= DRAIN
} else {
- if (damage < 0.02) {
- m.damage(damage)
- } else if (m.immuneCycle < m.cycle) {
- m.immuneCycle = m.cycle + tech.collisionImmuneCycles;
- m.damage(damage)
- simulation.drawList.push({ //add dmg to draw queue
- x: player.position.x,
- y: player.position.y,
- radius: damage * 1500,
- color: simulation.mobDmgColor,
- time: 20
- });
- }
+ m.damage(damage * (tech.isRadioactiveResistance ? 0.25 : 1))
}
//float
if (player.velocity.y > 5) player.force.y -= 0.95 * player.mass * simulation.g
@@ -1926,7 +1918,7 @@ const level = {
const doorWidth2 = 15 + Math.floor(100 * Math.random() * Math.random())
spawn.bodyRect(offset.x + 2050 - doorWidth2 / 2, offset.y - 175, doorWidth2, 165); //block door
} else {
- spawn.mapRect(offset.x + 2000, offset.y - 2800, 100, 2800); //right wall
+ spawn.mapRect(offset.x + 2000, offset.y - 2800, 100, 2900); //right wall
}
}
@@ -2086,7 +2078,7 @@ const level = {
},
testing() {
// const button = level.button(200, -700)
- const toggle = level.toggle(200, -700)
+ // const toggle = level.toggle(200, -700)
level.custom = () => {
// button.draw();
ctx.fillStyle = "rgba(0,255,255,0.1)";
@@ -2096,7 +2088,7 @@ const level = {
level.enter.draw();
};
level.customTopLayer = () => {
- toggle.query();
+ // toggle.query();
};
level.setPosToSpawn(0, -750); //normal spawn
@@ -2127,11 +2119,9 @@ const level = {
function blockDoor(x, y, blockSize = 58) {
spawn.mapRect(x, y - 290, 40, 60); // door lip
spawn.mapRect(x, y, 40, 50); // door lip
- for (let i = 0; i < 4; ++i) {
- spawn.bodyRect(x + 5, y - 260 + i * blockSize, 30, blockSize);
- }
+ for (let i = 0; i < 4; ++i) spawn.bodyRect(x + 5, y - 260 + i * blockSize, 30, blockSize);
}
- blockDoor(710, -710);
+ // blockDoor(710, -710);
// for (let i = 0; i < 30; i++) powerUps.directSpawn(710, -710, "tech");
spawn.mapRect(2500, -1200, 200, 750); //right wall
@@ -2151,10 +2141,10 @@ const level = {
// spawn.shooterBoss(1900, -500)
// spawn.historyBoss(1200, -500)
// spawn.laserTargetingBoss(1600, -400)
- // spawn.striker(1600, -500)
+ spawn.hopper(1600, -500)
// spawn.laserTargetingBoss(1700, -120)
// spawn.bomberBoss(1400, -500)
- // spawn.ghoster(1800, -120)
+ spawn.hopBoss(1800, -120)
// spawn.streamBoss(1600, -500)
// spawn.orbitalBoss(1600, -500)
// spawn.cellBossCulture(1600, -500)
@@ -2962,8 +2952,6 @@ const level = {
button1.query();
button1.draw();
- hazard.query();
- hazard.level(button1.isUp)
rotor.rotate();
ctx.fillStyle = "hsl(175, 15%, 76%)"
@@ -4017,43 +4005,54 @@ const level = {
level.enter.draw();
};
+
+ // simulation.draw.mapPath = new Path2D();
+ // for (let i = 0, len = map.length; i < len; ++i) {
+ // let vertices = map[i].vertices;
+ // simulation.draw.mapPath.moveTo(vertices[0].x, vertices[0].y);
+ // for (let j = 1; j < vertices.length; j += 1) {
+ // simulation.draw.mapPath.lineTo(vertices[j].x, vertices[j].y);
+ // }
+ // simulation.draw.mapPath.lineTo(vertices[0].x, vertices[0].y);
+ // }
+ const lightingPath = new Path2D() //pre-draw the complex lighting path to save processing
+ lightingPath.moveTo(-1800, -500)
+ lightingPath.lineTo(-910, -500) //3rd floor light
+ lightingPath.lineTo(-1300, 0)
+ lightingPath.lineTo(-500, 0)
+ lightingPath.lineTo(-890, -500)
+ lightingPath.lineTo(-175, -500)
+ lightingPath.lineTo(-175, -250)
+ lightingPath.lineTo(175, -250)
+ lightingPath.lineTo(175, 0)
+ lightingPath.lineTo(-910, 100) //2nd floor light left
+ lightingPath.lineTo(-1300, 600)
+ lightingPath.lineTo(-500, 600)
+ lightingPath.lineTo(-890, 100)
+ lightingPath.lineTo(190, 100) //2nd floor light right
+ lightingPath.lineTo(-200, 600)
+ lightingPath.lineTo(600, 600)
+ lightingPath.lineTo(210, 100)
+ lightingPath.lineTo(1100, 100)
+ lightingPath.lineTo(1100, 1400)
+ lightingPath.lineTo(600, 1400) //1st floor light right
+ lightingPath.lineTo(10, 700)
+ lightingPath.lineTo(-10, 700)
+ lightingPath.lineTo(-600, 1400)
+ lightingPath.lineTo(-1950, 1400) //1st floor light left
+ lightingPath.lineTo(-2290, 950)
+ lightingPath.lineTo(-2310, 950)
+ lightingPath.lineTo(-2650, 1400)
+ lightingPath.lineTo(-3025, 1400)
+ lightingPath.lineTo(-3025, 150)
+ lightingPath.lineTo(-2590, 150)
+ lightingPath.lineTo(-2600, -150)
+ lightingPath.lineTo(-1800, -150)
+ lightingPath.lineTo(-1800, -500) //top left end/start of path
+
level.customTopLayer = () => {
ctx.fillStyle = "rgba(0,0,0,0.15)"; //shadows and lights
- ctx.beginPath()
- ctx.moveTo(-1800, -500)
- ctx.lineTo(-910, -500) //3rd floor light
- ctx.lineTo(-1300, 0)
- ctx.lineTo(-500, 0)
- ctx.lineTo(-890, -500)
- ctx.lineTo(-175, -500)
- ctx.lineTo(-175, -250)
- ctx.lineTo(175, -250)
- ctx.lineTo(175, 0)
- ctx.lineTo(-910, 100) //2nd floor light left
- ctx.lineTo(-1300, 600)
- ctx.lineTo(-500, 600)
- ctx.lineTo(-890, 100)
- ctx.lineTo(190, 100) //2nd floor light right
- ctx.lineTo(-200, 600)
- ctx.lineTo(600, 600)
- ctx.lineTo(210, 100)
- ctx.lineTo(1100, 100)
- ctx.lineTo(1100, 1400)
- ctx.lineTo(600, 1400) //1st floor light right
- ctx.lineTo(10, 700)
- ctx.lineTo(-10, 700)
- ctx.lineTo(-600, 1400)
- ctx.lineTo(-1950, 1400) //1st floor light left
- ctx.lineTo(-2290, 950)
- ctx.lineTo(-2310, 950)
- ctx.lineTo(-2650, 1400)
- ctx.lineTo(-3025, 1400)
- ctx.lineTo(-3025, 150)
- ctx.lineTo(-2590, 150)
- ctx.lineTo(-2600, -150)
- ctx.lineTo(-1800, -150)
- ctx.lineTo(-1800, -500) //top left end/start of path
- ctx.fill()
+ ctx.fill(lightingPath);
};
level.setPosToSpawn(25, -55); //normal spawn
diff --git a/js/player.js b/js/player.js
index 4b9d2e4..8000520 100644
--- a/js/player.js
+++ b/js/player.js
@@ -495,7 +495,7 @@ const m = {
if (tech.isSlowFPS) dmg *= 0.8
// if (tech.isPiezo) dmg *= 0.85
if (tech.isHarmReduce && input.field && m.fieldCDcycle < m.cycle) dmg *= 0.4
- if (tech.isBotArmor) dmg *= 0.94 ** b.totalBots()
+ if (tech.isBotArmor) dmg *= 0.93 ** b.totalBots()
if (tech.isHarmArmor && m.lastHarmCycle + 600 > m.cycle) dmg *= 0.33;
if (tech.isNoFireDefense && m.cycle > m.fireCDcycle + 120) dmg *= 0.34
if (tech.energyRegen === 0) dmg *= 0.34
@@ -1682,6 +1682,9 @@ const m = {
} else if (tech.isIceField) {
m.energy -= 0.04;
b.iceIX(1)
+ } else if (tech.isDroneRadioactive) {
+ m.energy -= 1;
+ b.droneRadioactive({ 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) }, 25)
} else {
m.energy -= 0.45 * tech.droneEnergyReduction;
b.drone()
diff --git a/js/powerup.js b/js/powerup.js
index 2fee77a..a84de0c 100644
--- a/js/powerup.js
+++ b/js/powerup.js
@@ -736,7 +736,11 @@ const powerUps = {
//bonus power ups for clearing runs in the last game
if (level.levelsCleared === 0 && !simulation.isCheating && localSettings.levelsClearedLastGame > 1) {
- for (let i = 0; i < localSettings.levelsClearedLastGame / 3; i++) powerUps.spawn(m.pos.x, m.pos.y, "tech", false); //spawn a tech for levels cleared in last game
+ for (let i = 0; i < localSettings.levelsClearedLastGame / 3; i++) {
+ powerUps.spawn(m.pos.x, m.pos.y, "tech", false); //spawn a tech for levels cleared in last game
+ simulation.makeTextLog(`for (let i = 0; i < localSettings.levelsClearedLastGame / 3; i++)`);
+ simulation.makeTextLog(`{ powerUps.spawn(m.pos.x, m.pos.y, "tech") //simulation superposition }`);
+ }
localSettings.levelsClearedLastGame = 0 //after getting bonus power ups reset run history
localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
}
diff --git a/js/spawn.js b/js/spawn.js
index c4c39a4..de4f64b 100644
--- a/js/spawn.js
+++ b/js/spawn.js
@@ -170,13 +170,13 @@ const spawn = {
Matter.Body.setVelocity(this, { x: 0, y: 0 });
//aoe damage to player
- if (m.immuneCycle < m.cycle && Vector.magnitude(Vector.sub(player.position, this.position)) < this.radius && !tech.isNeutronImmune) {
- const DRAIN = 0.07
+ if (m.immuneCycle < m.cycle && Vector.magnitude(Vector.sub(player.position, this.position)) < this.radius) {
+ const DRAIN = tech.isRadioactiveResistance ? 0.07 * 0.25 : 0.07
if (m.energy > DRAIN) {
m.energy -= DRAIN
} else {
m.energy = 0;
- m.damage(0.007 * simulation.dmgScale)
+ m.damage((tech.isRadioactiveResistance ? 0.007 * 0.25 : 0.007) * simulation.dmgScale)
simulation.drawList.push({ //add dmg to draw queue
x: this.position.x,
y: this.position.y,
@@ -233,7 +233,7 @@ const spawn = {
y: me.position.y
},
bodyB: me,
- stiffness: 0.001,
+ stiffness: 1,
damping: 1
});
World.add(engine.world, me.constraint);
@@ -244,7 +244,7 @@ const spawn = {
me.memory = Infinity;
me.hasRunDeathScript = false
me.locatePlayer();
- const density = 0.25
+ const density = 0.23
Matter.Body.setDensity(me, density); //extra dense //normal is 0.001 //makes effective life much larger
// spawn.shield(me, x, y, 1);
me.onDeath = function() {
@@ -416,7 +416,7 @@ const spawn = {
}
} else if (this.mode !== 3) { //all three modes at once
this.cycle = 0;
- Matter.Body.setDensity(me, density); //extra dense //normal is 0.001 //makes effective life much larger
+ Matter.Body.setDensity(me, 10 * density); //extra dense //normal is 0.001 //makes effective life much larger
if (this.mode === 2) {
Matter.Body.scale(this, 5, 5);
} else {
@@ -1017,6 +1017,8 @@ const spawn = {
me.accelMag = 0.04;
me.g = 0.0017; //required if using 'gravity'
me.frictionAir = 0.01;
+ me.friction = 1
+ me.frictionStatic = 1
me.restitution = 0;
me.delay = 120 * simulation.CDScale;
me.randomHopFrequency = 200 + Math.floor(Math.random() * 150);
@@ -1032,7 +1034,7 @@ const spawn = {
const forceMag = (this.accelMag + this.accelMag * Math.random()) * this.mass;
const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x);
this.force.x += forceMag * Math.cos(angle);
- this.force.y += forceMag * Math.sin(angle) - (Math.random() * 0.07 + 0.02) * this.mass; //antigravity
+ this.force.y += forceMag * Math.sin(angle) - (Math.random() * 0.07 + 0.06) * this.mass; //antigravity
}
} else {
//randomly hob if not aware of player
@@ -1048,6 +1050,96 @@ const spawn = {
}
};
},
+ hopBoss(x, y, radius = 90) {
+ mobs.spawn(x, y, 5, radius, "rgb(0,200,180)");
+ let me = mob[mob.length - 1];
+ me.isBoss = true;
+ me.g = 0.005; //required if using 'gravity'
+ me.frictionAir = 0.01;
+ me.friction = 1
+ me.frictionStatic = 1
+ me.restitution = 0;
+ me.accelMag = 0.07;
+ me.delay = 120 * simulation.CDScale;
+ me.randomHopFrequency = 200
+ me.randomHopCD = simulation.cycle + me.randomHopFrequency;
+ // me.memory = 420;
+ me.isInAir = false
+ Matter.Body.setDensity(me, 0.03); //extra dense //normal is 0.001 //makes effective life much larger
+ spawn.shield(me, x, y, 1);
+ spawn.spawnOrbitals(me, radius + 60, 1)
+ me.onDeath = function() {
+ powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ };
+ me.lastSpeed = me.speed
+ me.do = function() {
+ this.gravity();
+ this.seePlayerCheck();
+ this.checkStatus();
+ if (this.seePlayer.recall) {
+ const deltaSpeed = this.lastSpeed - this.speed
+ this.lastSpeed = this.speed
+ if (deltaSpeed > 13 && this.speed < 5) { //if the player slows down greatly in one cycle
+ //damage and push player away, push away blocks
+ const range = 800 //Math.min(800, 50 * deltaSpeed)
+ for (let i = body.length - 1; i > -1; i--) {
+ if (!body[i].isNotHoldable) {
+ sub = Vector.sub(body[i].position, this.position);
+ dist = Vector.magnitude(sub);
+ if (dist < range) {
+ knock = Vector.mult(Vector.normalise(sub), Math.min(20, 50 * body[i].mass / dist));
+ body[i].force.x += knock.x;
+ body[i].force.y += knock.y;
+ }
+ }
+ }
+
+ simulation.drawList.push({ //draw radius
+ x: this.position.x,
+ y: this.position.y,
+ radius: range,
+ color: "rgba(0,200,180,0.6)",
+ time: 4
+ });
+ }
+
+ if (this.isInAir) {
+ if (this.velocity.y > -0.01 && Matter.Query.collides(this, map).length || Matter.Query.collides(this, body).length) { //not moving up, and has hit the map or a body
+ this.isInAir = false //landing
+ this.cd = simulation.cycle + this.delay
+
+ }
+ } else { //on ground
+ if (this.cd < simulation.cycle && (Matter.Query.collides(this, map).length || Matter.Query.collides(this, body).length)) { //jump
+ this.isInAir = true
+ const forceMag = (this.accelMag + this.accelMag * Math.random()) * this.mass;
+ const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x);
+ this.force.x += forceMag * Math.cos(angle);
+ this.force.y += forceMag * Math.sin(angle) - (Math.random() * 0.05 + 0.04) * this.mass; //antigravity
+ }
+ }
+
+ // if (this.cd < simulation.cycle && (Matter.Query.collides(this, map).length || Matter.Query.collides(this, body).length)) {
+ // this.cd = simulation.cycle + this.delay;
+ // const forceMag = (this.accelMag + this.accelMag * Math.random()) * this.mass;
+ // const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x);
+ // this.force.x += forceMag * Math.cos(angle);
+ // this.force.y += forceMag * Math.sin(angle) - (Math.random() * 0.05 + 0.04) * this.mass; //antigravity
+ // }
+ } else {
+ //randomly hob if not aware of player
+ if (this.randomHopCD < simulation.cycle && (Matter.Query.collides(this, map).length || Matter.Query.collides(this, body).length)) {
+ this.randomHopCD = simulation.cycle + this.randomHopFrequency;
+ //slowly change randomHopFrequency after each hop
+ this.randomHopFrequency = Math.max(100, this.randomHopFrequency + 200 * (0.5 - Math.random()));
+ const forceMag = (this.accelMag + this.accelMag * Math.random()) * this.mass * (0.5 + Math.random() * 0.2);
+ const angle = -Math.PI / 2 + (Math.random() - 0.5) * Math.PI;
+ this.force.x += forceMag * Math.cos(angle);
+ this.force.y += forceMag * Math.sin(angle) - (0.1 + 0.08 * Math.random()) * this.mass; //antigravity
+ }
+ }
+ };
+ },
spinner(x, y, radius = 30 + Math.ceil(Math.random() * 35)) {
mobs.spawn(x, y, 5, radius, "#000000");
let me = mob[mob.length - 1];
@@ -2063,7 +2155,7 @@ const spawn = {
y: me.position.y
},
bodyB: me,
- stiffness: 0.001,
+ stiffness: 1,
damping: 1
});
World.add(engine.world, me.constraint);
@@ -2575,8 +2667,8 @@ const spawn = {
y: me.position.y
},
bodyB: me,
- stiffness: 0.0002,
- damping: 1
+ stiffness: 0.00004,
+ damping: 0.1
});
World.add(engine.world, me.constraint);
}, 2000); //add in a delay in case the level gets flipped left right
@@ -2912,7 +3004,7 @@ const spawn = {
y: me.position.y
},
bodyB: me,
- stiffness: 0.001,
+ stiffness: 0.0001,
damping: 1
});
World.add(engine.world, me.constraint);
diff --git a/js/tech.js b/js/tech.js
index d8caa4d..b554971 100644
--- a/js/tech.js
+++ b/js/tech.js
@@ -177,7 +177,7 @@
if (tech.isOneGun && b.inventory.length < 2) dmg *= 1.22
if (tech.isNoFireDamage && m.cycle > m.fireCDcycle + 120) dmg *= 1.9
if (tech.isSpeedDamage) dmg *= 1 + Math.min(0.43, player.speed * 0.015)
- if (tech.isBotDamage) dmg *= 1 + 0.05 * b.totalBots()
+ if (tech.isBotDamage) dmg *= 1 + 0.06 * b.totalBots()
return dmg * tech.slowFire * tech.aimDamage
},
duplicationChance() {
@@ -716,7 +716,7 @@
},
requires: "an explosive damage source, not ammonium nitrate or nitroglycerin",
effect: () => {
- tech.isExplodeRadio = true;
+ tech.isExplodeRadio = true; //iridium-192
},
remove() {
tech.isExplodeRadio = false;
@@ -823,9 +823,9 @@
frequency: 2,
frequencyDefault: 2,
allowed() {
- return tech.haveGunCheck("missiles") || tech.isIncendiary || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.haveGunCheck("vacuum bomb") || tech.isMissileField || tech.isExplodeMob || tech.isPulseLaser || tech.isBlockExplosion
+ return !tech.isExplodeRadio && (tech.haveGunCheck("missiles") || tech.isIncendiary || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.haveGunCheck("vacuum bomb") || tech.isMissileField || tech.isExplodeMob || tech.isPulseLaser || tech.isBlockExplosion)
},
- requires: "an explosive damage source",
+ requires: "an explosive damage source, not iridium-192",
effect: () => {
tech.isImmuneExplosion = true;
},
@@ -841,9 +841,9 @@
frequency: 2,
frequencyDefault: 2,
allowed() {
- return ((m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing" && !(tech.isSporeField || tech.isMissileField || tech.isIceField)) || tech.haveGunCheck("drones") || tech.haveGunCheck("super balls") || tech.haveGunCheck("shotgun")) && !tech.isNailShot
+ return ((m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing" && !(tech.isDroneRadioactive || tech.isSporeField || tech.isMissileField || tech.isIceField)) || (tech.haveGunCheck("drones") && !tech.isDroneRadioactive) || tech.haveGunCheck("super balls") || tech.haveGunCheck("shotgun")) && !tech.isNailShot
},
- requires: "drones, super balls, shotgun",
+ requires: "super balls, shotgun, drones, not radioactive drones",
effect() {
tech.isIncendiary = true
},
@@ -1376,7 +1376,7 @@
},
{
name: "perimeter defense",
- description: "reduce harm by 6%
for each of your permanent bots",
+ description: "reduce harm by 7%
for each of your permanent bots",
maxCount: 1,
count: 0,
frequency: 2,
@@ -1394,7 +1394,7 @@
},
{
name: "network effect",
- description: "increase damage by 5%
for each of your permanent bots",
+ description: "increase damage by 6%
for each of your permanent bots",
maxCount: 1,
count: 0,
frequency: 2,
@@ -2509,7 +2509,7 @@
},
{
name: "negentropy",
- description: `at the start of each level
spawn a heal for every 33 missing health`,
+ description: `at the start of each level
spawn a heal for every 25 missing health`,
maxCount: 1,
count: 0,
frequency: 1,
@@ -4039,7 +4039,7 @@
},
{
name: "neutron bomb",
- description: "grenades are irradiated with Cf-252
does damage, harm, and drains energy",
+ description: "grenades are irradiated with Cf-252
does damage, harm, and drains energy",
isGunTech: true,
maxCount: 1,
count: 0,
@@ -4060,35 +4060,35 @@
},
{
name: "water shielding",
- description: "increase neutron bomb's range by 20%
you are immune to its harmful effects",
+ description: "radioactive effects on you are reduced by 75%
neutron bomb, drones, explosions, slime",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
- return tech.isNeutronBomb
+ return tech.isNeutronBomb || tech.isDroneRadioactive
},
- requires: "neutron bomb",
+ requires: "neutron bomb or radioactive drones",
effect() {
- tech.isNeutronImmune = true
+ tech.isRadioactiveResistance = true
},
remove() {
- tech.isNeutronImmune = false
+ tech.isRadioactiveResistance = false
}
},
{
name: "vacuum permittivity",
- description: "increase neutron bomb's range by 20%
objects in range of the bomb are slowed",
+ description: "increase radioactive range by 20%
objects in range of the bomb are slowed",
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
- return tech.isNeutronBomb
+ return tech.isNeutronBomb || tech.isDroneRadioactive
},
- requires: "neutron bomb",
+ requires: "neutron bomb or radioactive drones",
effect() {
tech.isNeutronSlow = true
},
@@ -4270,6 +4270,39 @@
tech.isMutualism = false
}
},
+ {
+ name: "radioisotope generator",
+ description: "irradiate drones, reduce ammo by 75%
does damage, harm, and drains energy",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("drones") && tech.droneCycleReduction === 1 && !tech.isIncendiary
+ },
+ requires: "drone gun, not reduced tolerances or incendiary",
+ effect() {
+ tech.isDroneRadioactive = true
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "drones") {
+ b.guns[i].ammoPack = b.guns[i].defaultAmmoPack * 0.25
+ b.guns[i].ammo = Math.ceil(b.guns[i].ammo * 0.25)
+ }
+ }
+ },
+ remove() {
+ if (tech.isDroneRadioactive) {
+ tech.isDroneRadioactive = false
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "drones") {
+ b.guns[i].ammoPack = b.guns[i].defaultAmmoPack
+ b.guns[i].ammo = b.guns[i].ammo * 4
+ }
+ }
+ }
+ }
+ },
{
name: "brushless motor",
description: "drones accelerate 50% faster",
@@ -4308,33 +4341,6 @@
tech.isDroneGrab = false
}
},
- {
- name: "reduced tolerances",
- description: "increase drone ammo/efficiency by 66%
reduce the average drone lifetime by 40%",
- isGunTech: true,
- maxCount: 3,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("drones") || (m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing" && !(tech.isSporeField || tech.isMissileField || tech.isIceField))
- },
- requires: "drones",
- effect() {
- tech.droneCycleReduction = Math.pow(0.6, 1 + this.count)
- tech.droneEnergyReduction = Math.pow(0.333, 1 + this.count)
- for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
- if (b.guns[i].name === "drones") b.guns[i].ammoPack = b.guns[i].defaultAmmoPack * Math.pow(3, this.count)
- }
- },
- remove() {
- tech.droneCycleReduction = 1
- tech.droneEnergyReduction = 1
- for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
- if (b.guns[i].name === "drones") b.guns[i].ammoPack = b.guns[i].defaultAmmoPack
- }
- }
- },
{
name: "drone repair",
description: "broken drones repair if the drone gun is active
repairing has a 33% chance to use 1 ammo",
@@ -4354,6 +4360,36 @@
tech.isDroneRespawn = false
}
},
+ {
+ name: "reduced tolerances",
+ description: "increase drone ammo/efficiency by 66%
reduce the average drone lifetime by 40%",
+ isGunTech: true,
+ maxCount: 3,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return !tech.isDroneRadioactive && (tech.haveGunCheck("drones") || (m.fieldUpgrades[m.fieldMode].name === "nano-scale manufacturing" && !(tech.isSporeField || tech.isMissileField || tech.isIceField)))
+ },
+ requires: "drones",
+ effect() {
+ tech.droneCycleReduction = Math.pow(0.6, 1 + this.count)
+ tech.droneEnergyReduction = Math.pow(0.333, 1 + this.count)
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "drones") {
+ const scale = Math.pow(3, this.count + 1)
+ b.guns[i].ammoPack = b.guns[i].defaultAmmoPack * scale
+ }
+ }
+ },
+ remove() {
+ tech.droneCycleReduction = 1
+ tech.droneEnergyReduction = 1
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "drones") b.guns[i].ammoPack = b.guns[i].defaultAmmoPack
+ }
+ }
+ },
{
name: "necrophoresis",
description: "foam bubbles grow and split into 3 copies
when the mob they are stuck to dies",
@@ -7209,5 +7245,6 @@
isBlockExplosion: null,
superBallDelay: null,
isBlockExplode: null,
- isOverHeal: null
+ isOverHeal: null,
+ isDroneRadioactive: null
}
\ No newline at end of file
diff --git a/todo.txt b/todo.txt
index 1ab5963..9fecfab 100644
--- a/todo.txt
+++ b/todo.txt
@@ -1,20 +1,22 @@
******************************************************** NEXT PATCH ********************************************************
-new level labs is done (it's kinda randomized, so expect it to feel different each run)
- (I know there are tons of bugs, but I figure we can find them together :)
+tech - radioisotope generator - drones have the effect of neutron bomb, but you get less ammo
+bug fix - reduced tolerances now properly gives extra ammo
+water shielding now protects you from all radioactivity, but only gives 75% protection
+ (drones, neutron bomb, radioactive explosions, and even slime)
-foam gun now gets about 20% less ammo
-new junk tech: "emergency broadcasting" - plays some fun sounds and gives you health
+final boss has more durability in it's final phase
+final boss no longers gets knocked around as much from explosions
-updated matter.js to a newer build matter-js 0.17.1 by @liabru
- (was matter-js 0.14.2 by @liabru 2018-06-11)
- matter.js patch notes suggest a possible 30% physics performance increase
- decomp.min.js was removed because I don't think it does anything anymore
- I did get one error message about it being missing, but there were other bugs too
+level.warehouse predraw lighting for performance
+bug fix on sewers where slime was doing too much harm
******************************************************** BUGS ********************************************************
-Final boss acts super weird when hit by explosions
+slime does extra damage on flipped levels?
+
+using time dilatation breaks constraints
+ on map n-gon, toggles
player can become crouched while not touching the ground if they exit the ground while crouched
@@ -38,9 +40,18 @@ is there a way to check if the player is stuck inside the map or block
******************************************************** LEVELS ********************************************************
+make a power up you can carry around like the heal power up when at full health
+ drop it on a map element to turn it on?
+ use it in combat?
+
labs - procedural generation
bugs
mob spawns shouldn't be based on probability?
+ style
+ graphics look too bright?
+ add shadows and lighting and graphic details?
+ what about performance?
+ with the mobs staggered spawning it should be fine
feel
disrupt the flat ground
less platforming / easier platforming
@@ -49,7 +60,13 @@ labs - procedural generation
is it laggy?
in loot room, spawn mobs after power up is grabbed
more background graphics, better colors
- science theme, with a cool technology showcased
+ loot room:
+ make it more interesting to get the power up
+ slow player and reduce damage in region
+ increase the size of the region
+ don't have space for much
+ make graphics more unique
+ push player away, so that normal pick up methods don't work, but add a button to disable region
room ideas -
portal room
endlessly falling blocks down a slide, that the player has to climb up
@@ -57,18 +74,95 @@ labs - procedural generation
slime room
sound room, with buttons to control sound
color room with r,g,b buttons to control color
- test fire room, button fires blocks at a wall
mob buff zone: Map element: "Orbital Pickup Zone": Mobs that enter a specific area of the map gain +1 orbital per second, or a shield
could put in the loot room
+buttons can now on/off boosts
+
+repeat map in vertical when you fall teleport to above the mab, as if the map repeats
+ camera looks strange when you teleport player with a high velocity
+
+map element - player rotates a rotor that makes a platform go up or down
+
+level element: a zone with wind, anti-gravity, extra gravity
+ control with button
+
+map: observatory
+ button controls rotation of telescope
+ laser beam shoots out of telescope
+ button opens the dome
+
+map: prison
+ doors linked to buttons
+ mobs inside the doors?
+
+boss levels - small levels just a boss, and maybe a few mobs
+ boss level for timeSkipBoss because of game instability for boss on normal levels
+ this might not fix issues
+
+******************************************************** MOBS ********************************************************
+
+mob mechanics
+ use the force at a location effect, like the plasma field
+
+mob - after taking damage
+ release seekers
+ teleports
+
+hop boss:
+ AoE damage when landing
+ pull in player? and blocks?
+ extra gravity on falling?
+ immune to damage while falling?
+
+mob: molecule shapes - 2 separate mobs joined by a bond
+ use constraints: just spawn 2x or 3x groupings
+ low friction so they can spin around
+ spin when attacking player?
+ increase constraint length when attacking
+
+mob vision: look at player history
+ build a new type of attraction for mobs
+ if mobs can't see player, they check to see if they can see where the player was in the history
+ if mobs can't see player, they could check to see if they can find player in the past
+ https://abitawake.com/news/articles/enemy-ai-chasing-a-player-without-navigation2d-or-a-star-pathfinding
+ write find in spawn undo exploder, but commented out
+
+Mob: "Tentacle": Sits on wall. Is a black blob. When you get near it, reaches out and grabs you, similar to wires. Does not deal damage.
+ maybe it could be immune to damage? but it is spawned by an actual mob
+
+level Boss: fractal Sierpiński triangle
+ https://en.wikipedia.org/wiki/Sierpi%C5%84ski_triangle
+ spawns a 1/2 size version of the boss, this version can also spawn a smaller version, but it is capped at some size level
+ they spawn once at the start of the level
+ if a version dies, one can be replaced every ten seconds by the largest version
+
+give mobs more animal-like behaviors like rain world
+ mobs play, look for food, explore
+ mobs some times aren't aggressive
+ when low on life or after taking a large hit
+ mobs can fight each other
+ this might be hard to code
+ isolated mobs try to group up
+
+mob: wall mounted guns / lasers
+ not part of randomized mob pool, customized to each level
+
+level boss: fires a line intersection in a random direction every few seconds.
+ the last two intersections have a destructive laser between them.
+
******************************************************** TODO ********************************************************
+tech foam teleports around, like a quantum wave function collapse
+
+should ammo apply to all guns, or just one of your guns?
+ if one gun only, it would make multi-gun builds weaker
+
+nail bots should benefit from nail gun tech
+
tech: picking up heal power ups at max health does harm, but increases max health
scales with heal value
-does catabolism give too much ammo?
- synergy with shotgun harm immunity
-
let standing wave harmonics get tech decorrelation
tech: cloaking field - decrease/increase cooldown on sneak attack?
@@ -88,24 +182,12 @@ tech plasma : plasma length increases then decreases as you hold down the field
tech: at the start of a new level remove 5 research and spawn a second boss
-what about the single axis graphic? (find the code in standing wave harmonic)
- maybe just save it for a mob
- maybe use it on lore
-
-buttons can now on/off boosts
-
energy conservation 6% damage recovered as energy
add a negative effect:
junk tech
Weak Anthropic Principle: you get a second chance at life, but ....
-mob: molecule shapes - 2 separate mobs joined by a bond
- use constraints: just spawn 2x or 3x groupings
- low friction so they can spin around
- spin when attacking player?
- increase constraint length when attacking
-
tech: use the ability for power ups to have custom code
(note: this code is half way done, it just needs to be completed)
attracted to player
@@ -137,31 +219,12 @@ apply the new gun.do functions to other guns
crouching missile?
works similar to foam
performance issues?
-
-tech plasma field - plasma field becomes an aoe damage field with the same radius
- 200% more energy drain, 100% more damage
- draw a square (or two) that rapidly spins
look into improving mouse lag with pointer lock?
https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API
https://www.vsynctester.com/game.html
https://news.ycombinator.com/item?id=26530272
-mob vision: look at player history
- build a new type of attraction for mobs
- if mobs can't see player, they check to see if they can see where the player was in the history
- if mobs can't see player, they could check to see if they can find player in the past
- https://abitawake.com/news/articles/enemy-ai-chasing-a-player-without-navigation2d-or-a-star-pathfinding
- write find in spawn undo exploder, but commented out
-
-Mob: "Tentacle": Sits on wall. Is a black blob. When you get near it, reaches out and grabs you, similar to wires. Does not deal damage.
- maybe it could be immune to damage? but it is spawned by an actual mob
-
-mob - after taking damage
- attack outwardly
- grows
- teleports
-
mobile requirements:
detect mobile, flip to landscape
detect no keyboard, no mouse
@@ -170,20 +233,12 @@ mobile requirements:
tap screen regions to move (WASD)
reduce font size
-lore: a tutorial / lore intro
- needs to be optional so it doesn't slow experienced players
- put something on the intro map
- maybe a button triggers something
-
add back in gamepad support
but does anyone care?
https://github.com/landgreen/landgreen.github.io/search?q=gamepadconnected
rename intro level to something lore related
-rename ?
- health -> integrity, unity
- heal -> also integrity, unity
RPG default or tech: grenades detonate on your cursor / where your cursor was when they were fired
@@ -219,18 +274,6 @@ tech pilot wave: antigravity - blocks have no gravity for a few seconds after ex
wormhole - make it clear when the wormhole can and can't teleport to a location before the player clicks
-flavor - your bullets destroy blocks
- this isn't really a bonus, so maybe just add this as flavor to another tech field/gun
- a chance for destroyed blocks to drop stuff
- power ups
- spores
-
-using a reroll gives 3 options for tech, and 3 options for guns/fields/tech
- or 6 options for tech (rewrite tech selection to work with 1-6 options)
- the second stack of 3 tech could have repeats, so you don't have to write new tech code
- adjust css to make 2 columns of 3
- can't use with cardinality
-
new power up - increase damage and fire speed, for 15 seconds
named boost?
enabled by a tech
@@ -242,9 +285,6 @@ tech- do 50% more damage in close, but 50% less at a distance
code it like techisFarAwayDmg
have these tech disable each other
-repeat map in vertical and horizontal space
- or at least vertical space
- camera looks strange when you teleport player with a high velocity
new status effect: weakness, mobs do 75% les damage
graphic indication?
@@ -267,45 +307,8 @@ look for tech that could update description text with count and tech is informat
can only use variables that change in effect() and remove()
this.description = `8% chance to duplicate spawned power ups
chance to duplicate = ${techduplicateChance}`
-map element - player rotates a rotor that makes a platform go up or down
-
use mac automator to speed up your n-gon -> git sync
-level Boss: fractal Sierpiński triangle
- https://en.wikipedia.org/wiki/Sierpi%C5%84ski_triangle
- spawns a 1/2 size version of the boss, this version can also spawn a smaller version, but it is capped at some size level
- they spawn once at the start of the level
- if a version dies, one can be replaced every ten seconds by the largest version
-
-level element: a zone with wind, anti-gravity, extra gravity
- control with button
-
-give mobs more animal-like behaviors like rain world
- mobs play, look for food, explore
- mobs some times aren't aggressive
- when low on life or after taking a large hit
- mobs can fight each other
- this might be hard to code
- isolated mobs try to group up
-
-mob: wall mounted guns / lasers
- not part of randomized mob pool, customized to each level
-
-level boss: fires a line intersection in a random direction every few seconds.
- the last two intersections have a destructive laser between them.
-
-map: observatory
- button controls rotation of telescope
- laser beam shoots out of telescope
- button opens the dome
-
-map: prison
- doors linked to buttons
- mobs inside the doors?
-
-graphic idea: bezier curve that moves smoothly from mob to mob
- loops around player
-
movement fluidity
let legs jump on mobs, but player will still take damage
like: ori and the blind forest, celeste
@@ -328,14 +331,6 @@ have a mob apply a positive status effect on other mobs,
damage bonus, but how?
possible balance issues
-boss levels - small levels just a boss, and maybe a few mobs
- boss level for timeSkipBoss because of game instability for boss on normal levels
- this might not fix issues
-
-an effect when canceling a power up
- ammo? heals?
- 50% chance for a tech 25% heal, 25% ammo
-
css transition for pause menu
animate new level spawn by having the map aspects randomly fly into place
@@ -344,6 +339,7 @@ n-gon outreach ideas
blips - errant signal on youtube
reddit - r/IndieGaming
hacker news - show hacker news post
+ twitch - lets play
******************************************************** LORE ********************************************************
@@ -369,6 +365,17 @@ possible names for tech
phlogiston theory is a superseded scientific theory that postulated the existence of a fire-like element called phlogiston
Laplace's demon was a notable published articulation of causal determinism on a scientific basis by Pierre-Simon Laplace in 1814.[1] According to determinism, if someone (the demon) knows the precise location and momentum of every atom in the universe, their past and future values for any given time are entailed; they can be calculated from the laws of classical mechanics.
Degenerate matter is a highly dense state of fermionic matter in which the Pauli exclusion principle exerts significant pressure in addition to, or in lieu of thermal pressure.
+ evolutionary cosmology
+ eternal inflation
+
+a tutorial / lore intro
+ needs to be optional so it doesn't slow experienced players
+ put something on the intro map
+ maybe a button triggers something
+
+rename ?
+ health -> integrity, unity
+ heal -> also integrity, unity
plot script: