diff --git a/.DS_Store b/.DS_Store
index 697f9d7..293fb18 100644
Binary files a/.DS_Store and b/.DS_Store differ
diff --git a/js/bullet.js b/js/bullet.js
index 750bbaf..7ba90f4 100644
--- a/js/bullet.js
+++ b/js/bullet.js
@@ -1241,7 +1241,7 @@ const b = {
},
minDmgSpeed: 0,
lookFrequency: Math.floor(7 + Math.random() * 3),
- density: 0.001, //0.001 is normal for blocks, 0.005 is normal for harpoon, 0.035 when buffed
+ density: 0.001, //0.001 is normal for blocks, 0.008 is normal for harpoon, 0.008*6 when buffed
beforeDmg(who) {
if (tech.isShieldPierce && who.isShielded) { //disable shields
who.isShielded = false
@@ -1343,7 +1343,7 @@ const b = {
Composite.add(engine.world, bullet[me]); //add bullet to world
},
- harpoon(where, target, angle = m.angle, harpoonSize = 1, isReturn = false, totalCycles = 15) {
+ harpoon(where, target, angle = m.angle, harpoonSize = 1, isReturn = false, totalCycles = 35) {
const me = bullet.length;
const returnRadius = 100 * Math.sqrt(harpoonSize)
bullet[me] = Bodies.fromVertices(where.x, where.y, [{ x: -40 * harpoonSize, y: 2 * harpoonSize, index: 0, isInternal: false }, { x: -40 * harpoonSize, y: -2 * harpoonSize, index: 1, isInternal: false }, { x: 50 * harpoonSize, y: -3 * harpoonSize, index: 3, isInternal: false }, { x: 30 * harpoonSize, y: 2 * harpoonSize, index: 4, isInternal: false }], {
@@ -1355,16 +1355,16 @@ const b = {
turnRate: isReturn ? 0.1 : 0.03, //0.015
drawStringControlMagnitude: 3000 + 5000 * Math.random(),
drawStringFlip: (Math.round(Math.random()) ? 1 : -1),
- dmg: 7, //damage done in addition to the damage from momentum
+ dmg: 6, //damage done in addition to the damage from momentum
classType: "bullet",
endCycle: simulation.cycle + totalCycles * 2.5 + 15,
collisionFilter: {
category: cat.bullet,
mask: tech.isShieldPierce ? cat.map | cat.body | cat.mob | cat.mobBullet : cat.map | cat.body | cat.mob | cat.mobBullet | cat.mobShield,
},
- minDmgSpeed: 0,
+ minDmgSpeed: 4,
lookFrequency: Math.floor(7 + Math.random() * 3),
- density: tech.harpoonDensity, //0.001 is normal for blocks, 0.005 is normal for harpoon, 0.035 when buffed
+ density: tech.harpoonDensity, //0.001 is normal for blocks, 0.006 is normal for harpoon, 0.006*6 when buffed
beforeDmg(who) {
if (tech.isShieldPierce && who.isShielded) { //disable shields
who.isShielded = false
@@ -1406,7 +1406,7 @@ const b = {
this.caughtPowerUp.effect();
Matter.Composite.remove(engine.world, this.caughtPowerUp);
powerUp.splice(index, 1);
- if (tech.isHarpoonPowerUp) tech.harpoonDensity = 0.008 * 6 //0.006 is normal
+ if (tech.isHarpoonPowerUp) tech.harpoonDensity = 0.006 * 6 //0.006 is normal
} else {
this.dropCaughtPowerUp()
}
@@ -1509,7 +1509,7 @@ const b = {
this.force.x -= returnForce.x
this.force.y -= returnForce.y
this.frictionAir = 0.002
- this.do = () => { this.force.y += this.mass * 0.001; }
+ this.do = () => { if (this.speed < 20) this.force.y += 0.0005 * this.mass; }
this.dropCaughtPowerUp()
} else { //return to player
this.do = this.returnToPlayer
@@ -1522,7 +1522,7 @@ const b = {
}
} else if (this.cycle > 30) {
this.frictionAir = 0.003
- this.do = () => { this.force.y += this.mass * 0.003; }
+ this.do = () => { if (this.speed < 20) this.force.y += 0.0005 * this.mass; }
}
if (target) { //rotate towards the target
@@ -1583,7 +1583,7 @@ const b = {
});
bullet[me].frictionAir = 0.002
bullet[me].do = function() {
- this.force.y += this.mass * 0.001; //gravity
+ if (this.speed < 20) this.force.y += 0.0005 * this.mass;
this.draw();
}
}
@@ -3492,43 +3492,66 @@ const b = {
}
},
randomBot(where = player.position, isKeep = true, isLaser = true) {
- if (tech.isNailBotUpgrade) { //check for upgrades first
- b.nailBot(where, isKeep)
- if (isKeep) tech.nailBotCount++;
- } else if (tech.isFoamBotUpgrade) {
- b.foamBot(where, isKeep)
- if (isKeep) tech.foamBotCount++;
- } else if (tech.isBoomBotUpgrade) {
- b.boomBot(where, isKeep)
- if (isKeep) tech.boomBotCount++;
- } else if (tech.isLaserBotUpgrade) {
- b.laserBot(where, isKeep)
- if (isKeep) tech.laserBotCount++;
- } else if (tech.isOrbitBotUpgrade) {
- b.orbitBot(where, isKeep);
- if (isKeep) tech.orbitBotCount++;
- } else if (tech.isDynamoBotUpgrade) {
- b.dynamoBot(where, isKeep)
- if (isKeep) tech.dynamoBotCount++;
- } else if (Math.random() < 0.166 && isLaser) { //random
- b.laserBot(where, isKeep)
- if (isKeep) tech.laserBotCount++;
- } else if (Math.random() < 0.2) {
- b.dynamoBot(where, isKeep)
- if (isKeep) tech.dynamoBotCount++;
- } else if (Math.random() < 0.25) {
- b.orbitBot(where, isKeep);
- if (isKeep) tech.orbitBotCount++;
- } else if (Math.random() < 0.33) {
- b.nailBot(where, isKeep)
- if (isKeep) tech.nailBotCount++;
- } else if (Math.random() < 0.5) {
- b.foamBot(where, isKeep)
- if (isKeep) tech.foamBotCount++;
- } else {
- b.boomBot(where, isKeep)
- if (isKeep) tech.boomBotCount++;
+ if (Math.random() < 0.5) { //chance to match scrap bot to your upgrade
+ if (tech.isNailBotUpgrade) { //check for upgrades first
+ b.nailBot(where, isKeep)
+ if (isKeep) tech.nailBotCount++;
+ } else if (tech.isFoamBotUpgrade) {
+ b.foamBot(where, isKeep)
+ if (isKeep) tech.foamBotCount++;
+ } else if (tech.isBoomBotUpgrade) {
+ b.boomBot(where, isKeep)
+ if (isKeep) tech.boomBotCount++;
+ } else if (tech.isLaserBotUpgrade) {
+ b.laserBot(where, isKeep)
+ if (isKeep) tech.laserBotCount++;
+ } else if (tech.isOrbitBotUpgrade) {
+ b.orbitBot(where, isKeep);
+ if (isKeep) tech.orbitBotCount++;
+ } else if (tech.isDynamoBotUpgrade) {
+ b.dynamoBot(where, isKeep)
+ if (isKeep) tech.dynamoBotCount++;
+ } else if (Math.random() < 0.166 && isLaser) { //random
+ b.laserBot(where, isKeep)
+ if (isKeep) tech.laserBotCount++;
+ } else if (Math.random() < 0.2) {
+ b.dynamoBot(where, isKeep)
+ if (isKeep) tech.dynamoBotCount++;
+ } else if (Math.random() < 0.25) {
+ b.orbitBot(where, isKeep);
+ if (isKeep) tech.orbitBotCount++;
+ } else if (Math.random() < 0.33) {
+ b.nailBot(where, isKeep)
+ if (isKeep) tech.nailBotCount++;
+ } else if (Math.random() < 0.5) {
+ b.foamBot(where, isKeep)
+ if (isKeep) tech.foamBotCount++;
+ } else {
+ b.boomBot(where, isKeep)
+ if (isKeep) tech.boomBotCount++;
+ }
+ } else { //else don't match scrap bot to upgrade
+ if (Math.random() < 0.166 && isLaser) { //random
+ b.laserBot(where, isKeep)
+ if (isKeep) tech.laserBotCount++;
+ } else if (Math.random() < 0.2) {
+ b.dynamoBot(where, isKeep)
+ if (isKeep) tech.dynamoBotCount++;
+ } else if (Math.random() < 0.25) {
+ b.orbitBot(where, isKeep);
+ if (isKeep) tech.orbitBotCount++;
+ } else if (Math.random() < 0.33) {
+ b.nailBot(where, isKeep)
+ if (isKeep) tech.nailBotCount++;
+ } else if (Math.random() < 0.5) {
+ b.foamBot(where, isKeep)
+ if (isKeep) tech.foamBotCount++;
+ } else {
+ b.boomBot(where, isKeep)
+ if (isKeep) tech.boomBotCount++;
+ }
}
+
},
setDynamoBotDelay() {
//reorder orbital bot positions around a circle
@@ -5481,8 +5504,8 @@ const b = {
name: "drones",
description: "deploy drones that crash into mobs
crashes reduce their lifespan by 1 second",
ammo: 0,
- ammoPack: 14.5,
- defaultAmmoPack: 14.5,
+ ammoPack: 16,
+ defaultAmmoPack: 16,
have: false,
do() {},
fire() {
@@ -5581,10 +5604,148 @@ const b = {
name: "harpoon",
description: "fire a self-steering harpoon that uses energy
to retract and refund its ammo cost",
ammo: 0,
- ammoPack: 0.3,
+ ammoPack: 0.6, //update this in railgun tech
have: false,
+ fire() {},
do() {},
- fire() {
+ chooseFireMethod() {
+ if (tech.isRailGun) {
+ this.do = this.railDo
+ this.fire = this.railFire
+ } else {
+ this.do = () => {}
+ this.fire = this.harpoonFire
+ }
+ },
+ charge: 0,
+ railDo() {
+ if (this.charge > 0) {
+ //exit railgun charging without firing
+ if (m.energy < 0.005 && !tech.isRailEnergyGain) {
+ m.energy += 0.025 + this.charge * 0.11
+ m.fireCDcycle = m.cycle + 120; // cool down if out of energy
+ this.endCycle = 0;
+ this.charge = 0
+ b.refundAmmo()
+ return
+ }
+ //fire
+ if ((!input.fire && this.charge > 0.6)) {
+ const where = {
+ x: m.pos.x + 30 * Math.cos(m.angle),
+ y: m.pos.y + 30 * Math.sin(m.angle)
+ }
+ const closest = {
+ distance: 10000,
+ target: null
+ }
+ //look for closest mob in player's LoS
+ const dir = { x: Math.cos(m.angle), y: Math.sin(m.angle) }; //make a vector for the player's direction of length 1; used in dot product
+ const harpoonSize = tech.isLargeHarpoon ? 1 + 0.1 * Math.sqrt(this.ammo) : 1
+ for (let i = 0, len = mob.length; i < len; ++i) {
+ if (mob[i].alive && !mob[i].isBadTarget && Matter.Query.ray(map, m.pos, mob[i].position).length === 0) {
+ const dot = Vector.dot(dir, Vector.normalise(Vector.sub(mob[i].position, m.pos))) //the dot product of diff and dir will return how much over lap between the vectors
+ const dist = Vector.magnitude(Vector.sub(where, mob[i].position))
+ if (dist < closest.distance && dot > 0.88) { //target closest mob that player is looking at and isn't too close to target
+ closest.distance = dist
+ closest.target = mob[i]
+ }
+ }
+ }
+ tech.harpoonDensity = 0.01 //0.001 is normal for blocks, 0.006 is normal for harpoon, 0.006*6 when buffed
+ b.harpoon(where, closest.target, m.angle, harpoonSize, false)
+
+ //push away blocks and mobs
+ const range = 1200 * this.charge
+ for (let i = 0, len = mob.length; i < len; ++i) { //push away mobs when firing
+ const SUB = Vector.sub(mob[i].position, m.pos)
+ const DISTANCE = Vector.magnitude(SUB)
+ if (DISTANCE < range) {
+ const DEPTH = Math.min(range - DISTANCE, 1500)
+ const FORCE = Vector.mult(Vector.normalise(SUB), 0.0015 * Math.sqrt(DEPTH) * mob[i].mass)
+ mob[i].force.x += FORCE.x;
+ mob[i].force.y += FORCE.y;
+ }
+ }
+ for (let i = 0, len = body.length; i < len; ++i) { //push away blocks when firing
+ const SUB = Vector.sub(body[i].position, m.pos)
+ const DISTANCE = Vector.magnitude(SUB)
+ if (DISTANCE < range) {
+ const DEPTH = Math.min(range - DISTANCE, 500)
+ const FORCE = Vector.mult(Vector.normalise(SUB), 0.003 * Math.sqrt(DEPTH) * body[i].mass)
+ body[i].force.x += FORCE.x;
+ body[i].force.y += FORCE.y - body[i].mass * simulation.g * 1.5; //kick up a bit to give them some arc
+ }
+ }
+ for (let i = 0, len = powerUp.length; i < len; ++i) { //push away blocks when firing
+ const SUB = Vector.sub(powerUp[i].position, m.pos)
+ const DISTANCE = Vector.magnitude(SUB)
+ if (DISTANCE < range) {
+ const DEPTH = Math.min(range - DISTANCE, 500)
+ const FORCE = Vector.mult(Vector.normalise(SUB), 0.002 * Math.sqrt(DEPTH) * powerUp[i].mass)
+ powerUp[i].force.x += FORCE.x;
+ powerUp[i].force.y += FORCE.y - powerUp[i].mass * simulation.g * 1.5; //kick up a bit to give them some arc
+ }
+ }
+
+ const recoil = Vector.mult(Vector.normalise(Vector.sub(where, m.pos)), input.down ? 0.03 : 0.06)
+ player.force.x -= recoil.x
+ player.force.y -= recoil.y
+ tech.harpoonDensity = 0.006 //0.001 is normal for blocks, 0.006 is normal for harpoon, 0.006*6 when buffed
+
+ this.charge = 0;
+ } else { //charging
+ if (tech.isFireMoveLock) {
+ Matter.Body.setVelocity(player, {
+ x: 0,
+ y: -55 * player.mass * simulation.g //undo gravity before it is added
+ });
+ player.force.x = 0
+ player.force.y = 0
+ }
+ m.fireCDcycle = m.cycle + 10 //can't fire until mouse is released
+ const previousCharge = this.charge
+ //small b.fireCDscale = faster shots, b.fireCDscale=1 = normal shot, big b.fireCDscale = slower chot
+ let smoothRate = tech.isCapacitor ? 0.85 : Math.min(0.998, 0.985 * (0.98 + 0.02 * b.fireCDscale))
+ if (input.down) smoothRate *= 0.995
+
+ this.charge = this.charge * smoothRate + 1 - smoothRate
+ m.energy += (this.charge - previousCharge) * (tech.isRailEnergyGain ? 0.8 : -0.3) //energy drain is proportional to charge gained, but doesn't stop normal m.fieldRegen
+
+ //draw magnetic field
+ const X = m.pos.x
+ const Y = m.pos.y
+ const unitVector = { x: Math.cos(m.angle), y: Math.sin(m.angle) }
+ const unitVectorPerp = Vector.perp(unitVector)
+
+ function magField(mag, arc) {
+ ctx.moveTo(X, Y);
+ ctx.bezierCurveTo(
+ X + unitVector.x * mag, Y + unitVector.y * mag,
+ X + unitVector.x * mag + unitVectorPerp.x * arc, Y + unitVector.y * mag + unitVectorPerp.y * arc,
+ X + unitVectorPerp.x * arc, Y + unitVectorPerp.y * arc)
+ ctx.bezierCurveTo(
+ X - unitVector.x * mag + unitVectorPerp.x * arc, Y - unitVector.y * mag + unitVectorPerp.y * arc,
+ X - unitVector.x * mag, Y - unitVector.y * mag,
+ X, Y)
+ }
+ ctx.fillStyle = `rgba(50,0,100,0.05)`;
+ for (let i = 3; i < 7; i++) {
+ const MAG = 8 * i * i * this.charge * (0.93 + 0.07 * Math.random())
+ const ARC = 6 * i * i * this.charge * (0.93 + 0.07 * Math.random())
+ ctx.beginPath();
+ magField(MAG, ARC)
+ magField(MAG, -ARC)
+ ctx.fill();
+ }
+ }
+ }
+ },
+ railFire() {
+ m.fireCDcycle = m.cycle + 10 //can't fire until mouse is released
+ this.charge += 0.00001
+ },
+ harpoonFire() {
const where = {
x: m.pos.x + 30 * Math.cos(m.angle),
y: m.pos.y + 30 * Math.sin(m.angle)
@@ -5595,247 +5756,10 @@ const b = {
}
//look for closest mob in player's LoS
const dir = { x: Math.cos(m.angle), y: Math.sin(m.angle) }; //make a vector for the player's direction of length 1; used in dot product
- const harpoonSize = tech.isLargeHarpoon ? 1 + 0.1 * Math.sqrt(this.ammo) : 1
+ const harpoonSize = (tech.isLargeHarpoon ? 1 + 0.1 * Math.sqrt(this.ammo) : 1) //* (input.down ? 0.7 : 1)
const totalCycles = 7 * (tech.isFilament ? 1 + 0.01 * Math.min(110, this.ammo) : 1) * Math.sqrt(harpoonSize)
- if (input.down) { //railgun
- // if (true) {
- function pushAway(range) { //push away blocks when firing
- for (let i = 0, len = mob.length; i < len; ++i) {
- const SUB = Vector.sub(mob[i].position, m.pos)
- const DISTANCE = Vector.magnitude(SUB)
- if (DISTANCE < range) {
- const DEPTH = Math.min(range - DISTANCE, 1500)
- const FORCE = Vector.mult(Vector.normalise(SUB), 0.001 * Math.sqrt(DEPTH) * mob[i].mass)
- mob[i].force.x += FORCE.x;
- mob[i].force.y += FORCE.y;
- }
- }
- for (let i = 0, len = body.length; i < len; ++i) {
- const SUB = Vector.sub(body[i].position, m.pos)
- const DISTANCE = Vector.magnitude(SUB)
- if (DISTANCE < range) {
- const DEPTH = Math.min(range - DISTANCE, 500)
- const FORCE = Vector.mult(Vector.normalise(SUB), 0.002 * Math.sqrt(DEPTH) * body[i].mass)
- body[i].force.x += FORCE.x;
- body[i].force.y += FORCE.y - body[i].mass * simulation.g * 1.5; //kick up a bit to give them some arc
- }
- }
- }
- const me = bullet.length;
- bullet[me] = Bodies.rectangle(0, 0, 0.015, 0.0015, { //start as a small shape that can't even be seen
- vertexGoal: [{ x: -40 * harpoonSize, y: 2 * harpoonSize, index: 0, isInternal: false }, { x: -40 * harpoonSize, y: -2 * harpoonSize, index: 1, isInternal: false }, { x: 50 * harpoonSize, y: -3 * harpoonSize, index: 3, isInternal: false }, { x: 30 * harpoonSize, y: 2 * harpoonSize, index: 4, isInternal: false }],
- density: 0.03, //0.001 is normal
- restitution: 0,
- frictionAir: 0,
- dmg: 0, //damage done in addition to the damage from momentum
- classType: "bullet",
- collisionFilter: {
- category: 0,
- mask: cat.map | cat.body | cat.mob | cat.mobBullet | cat.mobShield
- },
- minDmgSpeed: 5,
- beforeDmg(who) {
- if (tech.isShieldPierce && who.isShielded) { //disable shields
- who.isShielded = false
- requestAnimationFrame(() => { who.isShielded = true });
- }
- if (who.shield && !tech.isShieldPierce) {
- for (let i = 0, len = mob.length; i < len; i++) {
- if (mob[i].id === who.shieldTargetID) { //apply some knock back to shield mob before shield breaks
- Matter.Body.setVelocity(mob[i], Vector.mult(Vector.normalise(this.velocity), 10));
- break
- }
- }
- Matter.Body.setVelocity(this, { x: -0.4 * this.velocity.x, y: -0.4 * this.velocity.y });
- } else {
- if (tech.fragments && this.speed > 10) {
- b.targetedNail(this.position, tech.fragments * 13)
- this.endCycle = 0 //triggers despawn
- }
- }
- },
- onEnd() {}
- });
- m.fireCDcycle = Infinity; // cool down
- Composite.add(engine.world, bullet[me]); //add bullet to world
- bullet[me].endCycle = Infinity
- bullet[me].charge = 0;
- bullet[me].do = function() {
- if (m.energy < 0.005 && !tech.isRailEnergyGain) {
- m.energy += 0.05 + this.charge * 0.2
- m.fireCDcycle = m.cycle + 120; // cool down if out of energy
- this.endCycle = 0;
- b.refundAmmo()
- return
- }
-
- if ((!input.fire && this.charge > 0.6)) { //fire on mouse release or on low energy
- // if (tech.isDarts) {
- // for (let i = 0; i < 5; i++) {
- // b.dart(where, m.angle + 0.1 * i)
- // b.dart(where, m.angle - 0.1 * i)
- // }
- // }
- Matter.Body.setVertices(this, this.vertexGoal) //take on harpoon shape
- m.fireCDcycle = m.cycle + 2; // set fire cool down
- //normal bullet behavior occurs after firing, overwrites this function
- this.endCycle = simulation.cycle + 140
- this.collisionFilter.category = cat.bullet
- Matter.Body.setPosition(this, { x: m.pos.x, y: m.pos.y })
- Matter.Body.setAngle(this, m.angle)
- const speed = 120
- Matter.Body.setVelocity(this, {
- x: m.Vx / 2 + speed * this.charge * Math.cos(m.angle),
- y: m.Vy / 2 + speed * this.charge * Math.sin(m.angle)
- });
- this.do = function() {
- this.force.y += this.mass * 0.0003 / this.charge; // low gravity that scales with charge
- }
- const KNOCK = ((input.down) ? 0.1 : 0.5) * this.charge * this.charge
- player.force.x -= KNOCK * Math.cos(m.angle)
- player.force.y -= KNOCK * Math.sin(m.angle) * 0.35 //reduce knock back in vertical direction to stop super jumps
- pushAway(1200 * this.charge)
- } else { // charging on mouse down
- if (tech.isFireMoveLock) {
- Matter.Body.setVelocity(player, {
- x: 0,
- y: -55 * player.mass * simulation.g //undo gravity before it is added
- });
- player.force.x = 0
- player.force.y = 0
- }
-
- m.fireCDcycle = Infinity //can't fire until mouse is released
- const previousCharge = this.charge
- //small b.fireCDscale = faster shots, b.fireCDscale=1 = normal shot, big b.fireCDscale = slower chot
- let smoothRate = tech.isCapacitor ? 0.93 : Math.min(0.998, 0.985 * (0.98 + 0.02 * b.fireCDscale))
-
- this.charge = this.charge * smoothRate + 1 - smoothRate
- m.energy += (this.charge - previousCharge) * (tech.isRailEnergyGain ? 10 : -0.5) //energy drain is proportional to charge gained, but doesn't stop normal m.fieldRegen
- //draw targeting
- let best;
- let range = 3000
- const dir = m.angle
- const path = [{
- x: m.pos.x + 20 * Math.cos(dir),
- y: m.pos.y + 20 * Math.sin(dir)
- },
- {
- x: m.pos.x + range * Math.cos(dir),
- y: m.pos.y + range * Math.sin(dir)
- }
- ];
- const vertexCollision = function(v1, v1End, domain) {
- for (let i = 0; i < domain.length; ++i) {
- let vertices = domain[i].vertices;
- const len = vertices.length - 1;
- for (let j = 0; j < len; j++) {
- results = simulation.checkLineIntersection(v1, v1End, vertices[j], vertices[j + 1]);
- if (results.onLine1 && results.onLine2) {
- const dx = v1.x - results.x;
- const dy = v1.y - results.y;
- const dist2 = dx * dx + dy * dy;
- if (dist2 < best.dist2) {
- best = {
- x: results.x,
- y: results.y,
- dist2: dist2,
- who: domain[i],
- v1: vertices[j],
- v2: vertices[j + 1]
- };
- }
- }
- }
- results = simulation.checkLineIntersection(v1, v1End, vertices[0], vertices[len]);
- if (results.onLine1 && results.onLine2) {
- const dx = v1.x - results.x;
- const dy = v1.y - results.y;
- const dist2 = dx * dx + dy * dy;
- if (dist2 < best.dist2) {
- best = {
- x: results.x,
- y: results.y,
- dist2: dist2,
- who: domain[i],
- v1: vertices[0],
- v2: vertices[len]
- };
- }
- }
- }
- };
-
- //check for collisions
- best = { x: null, y: null, dist2: Infinity, who: null, v1: null, v2: null };
- vertexCollision(path[0], path[1], mob);
- vertexCollision(path[0], path[1], map);
- vertexCollision(path[0], path[1], body);
- if (best.dist2 != Infinity) path[path.length - 1] = { x: best.x, y: best.y }; //if hitting something
- //draw beam
- ctx.beginPath();
- ctx.moveTo(path[0].x, path[0].y);
- ctx.lineTo(path[1].x, path[1].y);
- ctx.strokeStyle = `rgba(100,0,180,0.7)`;
- ctx.lineWidth = this.charge * 1
- ctx.setLineDash([10, 20]);
- ctx.stroke();
- ctx.setLineDash([]);
- //draw magnetic field
- const X = m.pos.x
- const Y = m.pos.y
- const unitVector = { x: Math.cos(m.angle), y: Math.sin(m.angle) }
- const unitVectorPerp = Vector.perp(unitVector)
-
- function magField(mag, arc) {
- ctx.moveTo(X, Y);
- ctx.bezierCurveTo(
- X + unitVector.x * mag, Y + unitVector.y * mag,
- X + unitVector.x * mag + unitVectorPerp.x * arc, Y + unitVector.y * mag + unitVectorPerp.y * arc,
- X + unitVectorPerp.x * arc, Y + unitVectorPerp.y * arc)
- ctx.bezierCurveTo(
- X - unitVector.x * mag + unitVectorPerp.x * arc, Y - unitVector.y * mag + unitVectorPerp.y * arc,
- X - unitVector.x * mag, Y - unitVector.y * mag,
- X, Y)
- }
- ctx.fillStyle = `rgba(50,0,100,0.05)`;
- for (let i = 3; i < 7; i++) {
- const MAG = 8 * i * i * this.charge * (0.93 + 0.07 * Math.random())
- const ARC = 6 * i * i * this.charge * (0.93 + 0.07 * Math.random())
- ctx.beginPath();
- magField(MAG, ARC)
- magField(MAG, -ARC)
- ctx.fill();
- }
- }
- }
- // } else {
-
- // // if (true) { //grappling hook, not working really
- // // if (m.immuneCycle < m.cycle + 60) m.immuneCycle = m.cycle + tech.collisionImmuneCycles; //player is immune to damage for 30 cycles
- // // b.harpoon(where, closest.target, m.angle, harpoonSize, false, 15)
- // // m.fireCDcycle = m.cycle + 50 * b.fireCDscale; // cool down
- // // const speed = 50
- // // const velocity = { x: speed * Math.cos(m.angle), y: speed * Math.sin(m.angle) }
- // // Matter.Body.setVelocity(player, velocity);
-
- // // } else {
-
- // for (let i = 0, len = mob.length; i < len; ++i) {
- // if (mob[i].alive && !mob[i].isBadTarget && Matter.Query.ray(map, m.pos, mob[i].position).length === 0) {
- // const dot = Vector.dot(dir, Vector.normalise(Vector.sub(mob[i].position, m.pos))) //the dot product of diff and dir will return how much over lap between the vectors
- // const dist = Vector.magnitude(Vector.sub(where, mob[i].position))
- // if (dist < closest.distance && dot > 0.95 && dist * dot * dot * dot * dot > 880) { //target closest mob that player is looking at and isn't too close to target
- // closest.distance = dist
- // closest.target = mob[i]
- // }
- // }
- // }
- // b.harpoon(where, closest.target, m.angle, harpoonSize, false, 15)
- // m.fireCDcycle = m.cycle + 50 * b.fireCDscale; // cool down
- // }
- } else if (tech.extraHarpoons) {
+ if (tech.extraHarpoons && !input.down) {
const range = 450 * (tech.isFilament ? 1 + 0.005 * Math.min(110, this.ammo) : 1)
let targetCount = 0
for (let i = 0, len = mob.length; i < len; ++i) {
@@ -5879,14 +5803,234 @@ const b = {
}
}
}
- b.harpoon(where, closest.target, m.angle, harpoonSize, true, totalCycles)
+ b.harpoon(where, closest.target, m.angle, harpoonSize, !input.down, totalCycles)
m.fireCDcycle = m.cycle + 90 //Infinity; // cool down
}
const recoil = Vector.mult(Vector.normalise(Vector.sub(where, m.pos)), input.down ? 0.015 : 0.035)
player.force.x -= recoil.x
player.force.y -= recoil.y
- tech.harpoonDensity = 0.008
- }
+ tech.harpoonDensity = 0.006 //0.001 is normal for blocks, 0.006 is normal for harpoon, 0.006*6 when buffed
+ },
+ // railGun2() {
+ // const where = {
+ // x: m.pos.x + 30 * Math.cos(m.angle),
+ // y: m.pos.y + 30 * Math.sin(m.angle)
+ // }
+ // const closest = {
+ // distance: 10000,
+ // target: null
+ // }
+ // //look for closest mob in player's LoS
+ // const dir = { x: Math.cos(m.angle), y: Math.sin(m.angle) }; //make a vector for the player's direction of length 1; used in dot product
+ // const harpoonSize = tech.isLargeHarpoon ? 1 + 0.1 * Math.sqrt(this.ammo) : 1
+ // const totalCycles = 7 * (tech.isFilament ? 1 + 0.01 * Math.min(110, this.ammo) : 1) * Math.sqrt(harpoonSize)
+
+ // function pushAway(range) { //push away blocks when firing
+ // for (let i = 0, len = mob.length; i < len; ++i) {
+ // const SUB = Vector.sub(mob[i].position, m.pos)
+ // const DISTANCE = Vector.magnitude(SUB)
+ // if (DISTANCE < range) {
+ // const DEPTH = Math.min(range - DISTANCE, 1500)
+ // const FORCE = Vector.mult(Vector.normalise(SUB), 0.001 * Math.sqrt(DEPTH) * mob[i].mass)
+ // mob[i].force.x += FORCE.x;
+ // mob[i].force.y += FORCE.y;
+ // }
+ // }
+ // for (let i = 0, len = body.length; i < len; ++i) {
+ // const SUB = Vector.sub(body[i].position, m.pos)
+ // const DISTANCE = Vector.magnitude(SUB)
+ // if (DISTANCE < range) {
+ // const DEPTH = Math.min(range - DISTANCE, 500)
+ // const FORCE = Vector.mult(Vector.normalise(SUB), 0.002 * Math.sqrt(DEPTH) * body[i].mass)
+ // body[i].force.x += FORCE.x;
+ // body[i].force.y += FORCE.y - body[i].mass * simulation.g * 1.5; //kick up a bit to give them some arc
+ // }
+ // }
+ // }
+
+ // const me = bullet.length;
+ // bullet[me] = Bodies.rectangle(0, 0, 0.015, 0.0015, { //start as a small shape that can't even be seen
+ // vertexGoal: [{ x: -40 * harpoonSize, y: 2 * harpoonSize, index: 0, isInternal: false }, { x: -40 * harpoonSize, y: -2 * harpoonSize, index: 1, isInternal: false }, { x: 50 * harpoonSize, y: -3 * harpoonSize, index: 3, isInternal: false }, { x: 30 * harpoonSize, y: 2 * harpoonSize, index: 4, isInternal: false }],
+ // density: 0.03, //0.001 is normal
+ // restitution: 0,
+ // frictionAir: 0,
+ // dmg: 0, //damage done in addition to the damage from momentum
+ // classType: "bullet",
+ // collisionFilter: {
+ // category: 0,
+ // mask: cat.map | cat.body | cat.mob | cat.mobBullet | cat.mobShield
+ // },
+ // minDmgSpeed: 5,
+ // beforeDmg(who) {
+ // if (tech.isShieldPierce && who.isShielded) { //disable shields
+ // who.isShielded = false
+ // requestAnimationFrame(() => { who.isShielded = true });
+ // }
+ // if (who.shield && !tech.isShieldPierce) {
+ // for (let i = 0, len = mob.length; i < len; i++) {
+ // if (mob[i].id === who.shieldTargetID) { //apply some knock back to shield mob before shield breaks
+ // Matter.Body.setVelocity(mob[i], Vector.mult(Vector.normalise(this.velocity), 10));
+ // break
+ // }
+ // }
+ // Matter.Body.setVelocity(this, { x: -0.4 * this.velocity.x, y: -0.4 * this.velocity.y });
+ // } else {
+ // if (tech.fragments && this.speed > 10) {
+ // b.targetedNail(this.position, tech.fragments * 13)
+ // this.endCycle = 0 //triggers despawn
+ // }
+ // }
+ // },
+ // onEnd() {}
+ // });
+ // m.fireCDcycle = Infinity; // cool down
+ // Composite.add(engine.world, bullet[me]); //add bullet to world
+ // bullet[me].endCycle = Infinity
+ // bullet[me].charge = 0;
+ // bullet[me].do = function() {
+ // if ((m.energy < 0.005 && !tech.isRailEnergyGain) || (!input.down && !tech.isRailGun)) {
+ // m.energy += 0.05 + this.charge * 0.2
+ // m.fireCDcycle = m.cycle + 120; // cool down if out of energy
+ // this.endCycle = 0;
+ // b.refundAmmo()
+ // return
+ // }
+
+ // if ((!input.fire && this.charge > 0.6)) { //fire on mouse release or on low energy
+ // Matter.Body.setVertices(this, this.vertexGoal) //take on harpoon shape
+ // m.fireCDcycle = m.cycle + 2; // set fire cool down
+ // //normal bullet behavior occurs after firing, overwrites this function
+ // this.endCycle = simulation.cycle + 140
+ // this.collisionFilter.category = cat.bullet
+ // Matter.Body.setPosition(this, { x: m.pos.x, y: m.pos.y })
+ // Matter.Body.setAngle(this, m.angle)
+ // const speed = 120
+ // Matter.Body.setVelocity(this, {
+ // x: m.Vx / 2 + speed * this.charge * Math.cos(m.angle),
+ // y: m.Vy / 2 + speed * this.charge * Math.sin(m.angle)
+ // });
+ // this.do = function() {
+ // this.force.y += this.mass * 0.0003 / this.charge; // low gravity that scales with charge
+ // }
+ // const KNOCK = ((input.down) ? 0.1 : 0.5) * this.charge * this.charge
+ // player.force.x -= KNOCK * Math.cos(m.angle)
+ // player.force.y -= KNOCK * Math.sin(m.angle) * 0.35 //reduce knock back in vertical direction to stop super jumps
+ // pushAway(1200 * this.charge)
+ // } else { // charging on mouse down
+ // if (tech.isFireMoveLock) {
+ // Matter.Body.setVelocity(player, {
+ // x: 0,
+ // y: -55 * player.mass * simulation.g //undo gravity before it is added
+ // });
+ // player.force.x = 0
+ // player.force.y = 0
+ // }
+
+ // m.fireCDcycle = Infinity //can't fire until mouse is released
+ // const previousCharge = this.charge
+ // //small b.fireCDscale = faster shots, b.fireCDscale=1 = normal shot, big b.fireCDscale = slower chot
+ // let smoothRate = tech.isCapacitor ? 0.85 : Math.min(0.998, 0.985 * (0.98 + 0.02 * b.fireCDscale))
+
+ // this.charge = this.charge * smoothRate + 1 - smoothRate
+ // m.energy += (this.charge - previousCharge) * (tech.isRailEnergyGain ? 1 : -0.25) //energy drain is proportional to charge gained, but doesn't stop normal m.fieldRegen
+ // //draw targeting
+ // let best;
+ // let range = 3000
+ // const dir = m.angle
+ // const path = [{
+ // x: m.pos.x + 20 * Math.cos(dir),
+ // y: m.pos.y + 20 * Math.sin(dir)
+ // },
+ // {
+ // x: m.pos.x + range * Math.cos(dir),
+ // y: m.pos.y + range * Math.sin(dir)
+ // }
+ // ];
+ // const vertexCollision = function(v1, v1End, domain) {
+ // for (let i = 0; i < domain.length; ++i) {
+ // let vertices = domain[i].vertices;
+ // const len = vertices.length - 1;
+ // for (let j = 0; j < len; j++) {
+ // results = simulation.checkLineIntersection(v1, v1End, vertices[j], vertices[j + 1]);
+ // if (results.onLine1 && results.onLine2) {
+ // const dx = v1.x - results.x;
+ // const dy = v1.y - results.y;
+ // const dist2 = dx * dx + dy * dy;
+ // if (dist2 < best.dist2) {
+ // best = {
+ // x: results.x,
+ // y: results.y,
+ // dist2: dist2,
+ // who: domain[i],
+ // v1: vertices[j],
+ // v2: vertices[j + 1]
+ // };
+ // }
+ // }
+ // }
+ // results = simulation.checkLineIntersection(v1, v1End, vertices[0], vertices[len]);
+ // if (results.onLine1 && results.onLine2) {
+ // const dx = v1.x - results.x;
+ // const dy = v1.y - results.y;
+ // const dist2 = dx * dx + dy * dy;
+ // if (dist2 < best.dist2) {
+ // best = {
+ // x: results.x,
+ // y: results.y,
+ // dist2: dist2,
+ // who: domain[i],
+ // v1: vertices[0],
+ // v2: vertices[len]
+ // };
+ // }
+ // }
+ // }
+ // };
+
+ // //check for collisions
+ // best = { x: null, y: null, dist2: Infinity, who: null, v1: null, v2: null };
+ // vertexCollision(path[0], path[1], mob);
+ // vertexCollision(path[0], path[1], map);
+ // vertexCollision(path[0], path[1], body);
+ // if (best.dist2 != Infinity) path[path.length - 1] = { x: best.x, y: best.y }; //if hitting something
+ // //draw beam
+ // ctx.beginPath();
+ // ctx.moveTo(path[0].x, path[0].y);
+ // ctx.lineTo(path[1].x, path[1].y);
+ // ctx.strokeStyle = `rgba(100,0,180,0.7)`;
+ // ctx.lineWidth = this.charge * 1
+ // ctx.setLineDash([10, 20]);
+ // ctx.stroke();
+ // ctx.setLineDash([]);
+ // //draw magnetic field
+ // const X = m.pos.x
+ // const Y = m.pos.y
+ // const unitVector = { x: Math.cos(m.angle), y: Math.sin(m.angle) }
+ // const unitVectorPerp = Vector.perp(unitVector)
+
+ // function magField(mag, arc) {
+ // ctx.moveTo(X, Y);
+ // ctx.bezierCurveTo(
+ // X + unitVector.x * mag, Y + unitVector.y * mag,
+ // X + unitVector.x * mag + unitVectorPerp.x * arc, Y + unitVector.y * mag + unitVectorPerp.y * arc,
+ // X + unitVectorPerp.x * arc, Y + unitVectorPerp.y * arc)
+ // ctx.bezierCurveTo(
+ // X - unitVector.x * mag + unitVectorPerp.x * arc, Y - unitVector.y * mag + unitVectorPerp.y * arc,
+ // X - unitVector.x * mag, Y - unitVector.y * mag,
+ // X, Y)
+ // }
+ // ctx.fillStyle = `rgba(50,0,100,0.05)`;
+ // for (let i = 3; i < 7; i++) {
+ // const MAG = 8 * i * i * this.charge * (0.93 + 0.07 * Math.random())
+ // const ARC = 6 * i * i * this.charge * (0.93 + 0.07 * Math.random())
+ // ctx.beginPath();
+ // magField(MAG, ARC)
+ // magField(MAG, -ARC)
+ // ctx.fill();
+ // }
+ // }
+ // }
+ // },
}, {
name: "mine",
description: "toss a proximity mine that sticks to walls
refund undetonated mines on exiting a level", //fires nails at mobs within range
diff --git a/js/level.js b/js/level.js
index adeff64..7d348e2 100644
--- a/js/level.js
+++ b/js/level.js
@@ -17,20 +17,20 @@ const level = {
// simulation.isHorizontalFlipped = true
// m.setField("time dilation")
// b.giveGuns("harpoon")
- // for (let i = 0; i < 100; i++) tech.giveTech("slow light")
- // tech.giveTech("tungsten carbide")
+ // tech.giveTech("unaaq")
+ // tech.giveTech("railgun")
+ // tech.giveTech("capacitor bank")
+ // tech.giveTech("half-wave rectifier")
+ // for (let i = 0; i < 1; i++) tech.giveTech("reticulum")
// for (let i = 0; i < 2; i++) powerUps.directSpawn(0, 0, "tech");
- // tech.giveTech("tinsellated flagella")
// for (let i = 0; i < 3; i++) tech.giveTech("undefined")
- // tech.giveTech("decoherence")
// for (let i = 10; i < tech.tech.length; i++) { tech.tech[i].isBanished = true }
// powerUps.research.changeRerolls(100000)
- // for (let i = 0; i < 1; i++) tech.giveTech("reticulum")
// for (let i = 0; i < 2; i++) tech.giveTech("laser-bot")
// tech.tech[297].frequency = 100
// m.immuneCycle = Infinity //you can't take damage
- // level.difficultyIncrease(15) //30 is near max on hard //60 is near max on why
+ // level.difficultyIncrease(8) //30 is near max on hard //60 is near max on why
// simulation.enableConstructMode() //used to build maps in testing mode
// level.reactor();
// level.testing(); //not in rotation, used for testing
@@ -128,30 +128,29 @@ const level = {
m.dmgScale = 1; //damage done by player decreases each level
simulation.accelScale = 1 //mob acceleration increases each level
simulation.CDScale = 1 //mob CD time decreases each level
- simulation.dmgScale = 0.375 * simulation.difficulty //damage done by mobs increases each level
+ simulation.dmgScale = Math.max(0.1, 0.35 * simulation.difficulty) //damage done by mobs scales with total levels
simulation.healScale = 1 / (1 + simulation.difficulty * 0.055) //a higher denominator makes for lower heals // m.health += heal * simulation.healScale;
},
difficultyIncrease(num = 1) {
for (let i = 0; i < num; i++) {
simulation.difficulty++
- m.dmgScale *= 0.92; //damage done by player decreases each level
+ m.dmgScale *= 0.925; //damage done by player decreases each level
if (simulation.accelScale < 6) simulation.accelScale *= 1.025 //mob acceleration increases each level
if (simulation.CDScale > 0.15) simulation.CDScale *= 0.965 //mob CD time decreases each level
}
- simulation.dmgScale = 0.375 * simulation.difficulty //damage done by mobs scales with total levels
+ simulation.dmgScale = Math.max(0.1, 0.35 * simulation.difficulty) //damage done by mobs scales with total levels
simulation.healScale = 1 / (1 + simulation.difficulty * 0.055) //a higher denominator makes for lower heals // m.health += heal * simulation.healScale;
// console.log(`CD = ${simulation.CDScale}`)
},
difficultyDecrease(num = 1) { //used in easy mode for simulation.reset()
for (let i = 0; i < num; i++) {
simulation.difficulty--
- m.dmgScale /= 0.92; //damage done by player decreases each level
+ m.dmgScale /= 0.925; //damage done by player decreases each level
if (simulation.accelScale > 1) simulation.accelScale /= 1.025 //mob acceleration increases each level
if (simulation.CDScale < 1) simulation.CDScale /= 0.965 //mob CD time decreases each level
}
if (simulation.difficulty < 1) simulation.difficulty = 0;
- simulation.dmgScale = 0.375 * simulation.difficulty //damage done by mobs scales with total levels
- if (simulation.dmgScale < 0.1) simulation.dmgScale = 0.1;
+ simulation.dmgScale = Math.max(0.1, 0.35 * simulation.difficulty) //damage done by mobs scales with total levels
simulation.healScale = 1 / (1 + simulation.difficulty * 0.055)
},
difficultyText() {
@@ -2701,11 +2700,11 @@ const level = {
if (!isSpawnedBoss) {
isSpawnedBoss = true
if (Math.random() < 0.33) {
- for (let i = 0, len = Math.min(simulation.difficulty / 20, 5); i < len; ++i) spawn.bounceBoss(1487 + 200 * i, -1525, 80, false);
+ for (let i = 0, len = Math.min(simulation.difficulty / 20, 6); i < len; ++i) spawn.bounceBoss(1487 + 200 * i, -1525, 80, false);
} else if (Math.random() < 0.5) {
- for (let i = 0, len = Math.min(simulation.difficulty / 10, 10); i < len; ++i) spawn.sprayBoss(2400 - 150 * i, -225, 30, false)
+ for (let i = 0, len = Math.min(simulation.difficulty / 9, 8); i < len; ++i) spawn.sprayBoss(2400 - 150 * i, -225, 30, false)
} else {
- for (let i = 0, len = Math.min(simulation.difficulty / 8, 10); i < len; ++i) spawn.mineBoss(1950, -250, 50, false);
+ for (let i = 0, len = Math.min(simulation.difficulty / 6, 10); i < len; ++i) spawn.mineBoss(1950, -250, 50, false);
}
// for (let i = 0, len = 3 + simulation.difficulty / 20; i < len; ++i) spawn.mantisBoss(1487 + 300 * i, -1525, 35, false)
}
diff --git a/js/player.js b/js/player.js
index df503f0..164af9e 100644
--- a/js/player.js
+++ b/js/player.js
@@ -2970,9 +2970,9 @@ const m = {
Matter.Composite.remove(engine.world, body[i]);
body.splice(i, 1);
m.fieldRange *= 0.8
- if (tech.isWormholeEnergy) m.energy += 0.63
+ if (tech.isWormholeEnergy) m.energy += 0.53
if (tech.isWormholeSpores) { //pandimensional spermia
- for (let i = 0, len = Math.ceil(3 * (tech.isSporeWorm ? 0.5 : 1) * Math.random()); i < len; i++) {
+ for (let i = 0, len = Math.ceil(2.5 * (tech.isSporeWorm ? 0.5 : 1) * Math.random()); i < len; i++) {
if (tech.isSporeWorm) {
b.worm(Vector.add(m.hole.pos2, Vector.rotate({
x: m.fieldRange * 0.4,
@@ -3004,9 +3004,9 @@ const m = {
body.splice(i, 1);
m.fieldRange *= 0.8
// if (tech.isWormholeEnergy && m.energy < m.maxEnergy * 2) m.energy = m.maxEnergy * 2
- if (tech.isWormholeEnergy && m.immuneCycle < m.cycle) m.energy += 0.63
+ if (tech.isWormholeEnergy && m.immuneCycle < m.cycle) m.energy += 0.53
if (tech.isWormholeSpores) { //pandimensional spermia
- for (let i = 0, len = Math.ceil(3 * (tech.isSporeWorm ? 0.5 : 1) * Math.random()); i < len; i++) {
+ for (let i = 0, len = Math.ceil(2.5 * (tech.isSporeWorm ? 0.5 : 1) * Math.random()); i < len; i++) {
if (tech.isSporeWorm) {
b.worm(Vector.add(m.hole.pos1, Vector.rotate({
x: m.fieldRange * 0.4,
diff --git a/js/simulation.js b/js/simulation.js
index 30b116a..a5a2f49 100644
--- a/js/simulation.js
+++ b/js/simulation.js
@@ -652,6 +652,7 @@ const simulation = {
if (b.guns[i].name === "laser") b.guns[i].chooseFireMethod()
if (b.guns[i].name === "nail gun") b.guns[i].chooseFireMethod()
if (b.guns[i].name === "super balls") b.guns[i].chooseFireMethod()
+ if (b.guns[i].name === "harpoon") b.guns[i].chooseFireMethod()
}
tech.dynamoBotCount = 0;
tech.nailBotCount = 0;
@@ -949,7 +950,7 @@ const simulation = {
if (!(m.cycle % 420)) { //once every 7 seconds
if (tech.isZeno) {
- m.health *= 0.9167 //remove 1/12
+ m.health *= 0.93 //remove 7%
m.displayHealth();
}
if (tech.cyclicImmunity && m.immuneCycle < m.cycle + tech.cyclicImmunity) m.immuneCycle = m.cycle + tech.cyclicImmunity; //player is immune to damage for 60 cycles
diff --git a/js/spawn.js b/js/spawn.js
index 7c1e786..a4c3098 100644
--- a/js/spawn.js
+++ b/js/spawn.js
@@ -3532,7 +3532,7 @@ const spawn = {
me.isBoss = true;
me.inertia = Infinity; //no rotation
// me.accelMag = 0.00008 + 0.00007 * simulation.accelScale;
- me.burstFireFreq = 20 + Math.floor(20 * simulation.CDScale)
+ me.burstFireFreq = 22 + Math.floor(22 * simulation.CDScale)
me.burstTotalPhases = 4 + Math.floor(2 / simulation.CDScale)
me.noFireTotalCycles = 390
me.frictionStatic = 0;
@@ -3602,10 +3602,10 @@ const spawn = {
}
}
if (this.phaseCycle > -1) {
- Matter.Body.rotate(this, 0.08)
+ Matter.Body.rotate(this, 0.02)
for (let i = 0, len = this.vertices.length; i < len; i++) { //fire a bullet from each vertex
spawn.sniperBullet(this.vertices[i].x, this.vertices[i].y, 8, 4);
- const velocity = Vector.mult(Vector.normalise(Vector.sub(this.position, this.vertices[i])), -26)
+ const velocity = Vector.mult(Vector.normalise(Vector.sub(this.position, this.vertices[i])), -20)
Matter.Body.setVelocity(mob[mob.length - 1], {
x: velocity.x,
y: velocity.y
@@ -3683,10 +3683,10 @@ const spawn = {
// this.isInvulnerable = true
// this.damageReduction = 0
} else {
- if (Math.abs(this.velocity.y) < 10) {
+ if (Math.abs(this.velocity.y) < 11) {
Matter.Body.setVelocity(this, { x: this.velocity.x, y: this.velocity.y * 1.03 });
}
- if (Math.abs(this.velocity.x) < 7) {
+ if (Math.abs(this.velocity.x) < 8) {
Matter.Body.setVelocity(this, { x: this.velocity.x * 1.03, y: this.velocity.y });
}
}
@@ -3729,6 +3729,7 @@ const spawn = {
me.explodeRange = 200 + 150 * Math.random()
me.isExploding = false
me.countDown = Math.ceil(4 * Math.random())
+ me.isInvulnerable = true //not actually invulnerable, just prevents block + ice-9 interaction
// me.onHit = function() {
// this.isExploding = true
@@ -3749,9 +3750,9 @@ const spawn = {
this.death();
//hit player
if (Vector.magnitude(Vector.sub(this.position, player.position)) < this.explodeRange) {
- m.damage(0.008 * simulation.dmgScale);
- const DRAIN = 0.08 * (tech.isRadioactiveResistance ? 0.25 : 1)
- if (m.energy > DRAIN) m.energy -= DRAIN
+ m.damage(0.01 * simulation.dmgScale * (tech.isRadioactiveResistance ? 0.25 : 1));
+ m.energy -= 0.1 * (tech.isRadioactiveResistance ? 0.25 : 1)
+ if (m.energy < 0) m.energy = 0
}
// mob[i].isInvulnerable = false //make mineBoss not invulnerable ?
const range = this.explodeRange + 50 //mines get a slightly larger range to explode
diff --git a/js/tech.js b/js/tech.js
index 91ad327..f3af3fb 100644
--- a/js/tech.js
+++ b/js/tech.js
@@ -2454,7 +2454,7 @@ const tech = {
},
{
name: "Zeno's paradox",
- description: "reduce harm by 85%, but every 5 seconds
remove 1/12 of your current health",
+ description: "reduce harm by 85%, but every 5 seconds
remove 7% of your current health",
// description: "every 5 seconds remove 1/10 of your health
reduce harm by 90%",
maxCount: 1,
count: 0,
@@ -3654,25 +3654,6 @@ const tech = {
tech.isNeedleIce = false
}
},
- {
- name: "ceramics",
- description: `needles and harpoons pierce shields
directly damaging shielded mobs`,
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("harpoon") || (tech.isNeedles || tech.isNeedleShot)
- },
- requires: "nail gun, needle gun, needle-shot, harpoon",
- effect() {
- tech.isShieldPierce = true
- },
- remove() {
- tech.isShieldPierce = false
- }
- },
{
name: "nanowires",
description: `needles tunnel through blocks and map
increase needle damage by 20%`,
@@ -4218,6 +4199,25 @@ const tech = {
tech.isIceShot = false;
}
},
+ {
+ name: "incendiary ammunition",
+ description: "shotgun, super balls, and drones
are loaded with explosives",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return ((m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && !(tech.isDroneTeleport || tech.isDroneRadioactive || tech.isSporeField || tech.isMissileField || tech.isIceField)) || (tech.haveGunCheck("drones") && !tech.isForeverDrones && !tech.isDroneRadioactive && !tech.isDroneTeleport) || tech.haveGunCheck("super balls") || tech.haveGunCheck("shotgun")) && !tech.isNailShot && !tech.isIceShot && !tech.isFoamShot && !tech.isWormShot && !tech.isNeedleShot
+ },
+ requires: "super balls, basic or slug shotgun, drones, not irradiated drones or burst drones",
+ effect() {
+ tech.isIncendiary = true
+ },
+ remove() {
+ tech.isIncendiary = false;
+ }
+ },
{
name: "supertemporal",
link: `supertemporal`,
@@ -4409,8 +4409,8 @@ const tech = {
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "matter wave") {
b.guns[i].chooseFireMethod()
- b.guns[i].ammoPack = b.guns[i].defaultAmmoPack / 8
- b.guns[i].ammo = Math.ceil(b.guns[i].ammo / 8);
+ b.guns[i].ammoPack = b.guns[i].defaultAmmoPack / 9
+ b.guns[i].ammo = Math.ceil(b.guns[i].ammo / 9);
simulation.updateGunHUD();
break
}
@@ -4423,7 +4423,7 @@ const tech = {
tech.isLongitudinal = false;
b.guns[i].chooseFireMethod()
b.guns[i].ammoPack = b.guns[i].defaultAmmoPack
- b.guns[i].ammo = Math.ceil(b.guns[i].ammo * 8);
+ b.guns[i].ammo = Math.ceil(b.guns[i].ammo * 9);
simulation.updateGunHUD();
break
}
@@ -4512,6 +4512,164 @@ const tech = {
}
}
},
+ {
+ name: "iridium-192",
+ description: "explosions release gamma radiation
100% more damage, but over 4 seconds",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.explosiveRadius === 1 && !tech.isSmallExplosion && (tech.haveGunCheck("missiles") || tech.isIncendiary || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.isPulseLaser || tech.isMissileField || tech.boomBotCount > 1 || tech.isTokamak)
+ },
+ requires: "an explosive damage source, not ammonium nitrate or nitroglycerin",
+ effect: () => {
+ tech.isExplodeRadio = true; //iridium-192
+ },
+ remove() {
+ tech.isExplodeRadio = false;
+ }
+ },
+ {
+ name: "fragmentation",
+ description: "some detonations and collisions eject nails
blocks, grenades, missiles, slugs, harpoon",
+ isGunTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return tech.haveGunCheck("harpoon") || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.haveGunCheck("missiles") || tech.missileBotCount || (tech.haveGunCheck("shotgun") && tech.isSlugShot) || tech.blockDamage > 0.075
+ },
+ requires: "grenades, missiles, shotgun slugs, harpoon, or mass driver",
+ effect() {
+ tech.fragments++
+ },
+ remove() {
+ tech.fragments = 0
+ }
+ },
+ {
+ name: "ammonium nitrate",
+ description: "increase explosive damage by 27%
increase explosive radius by 27%",
+ isGunTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return !tech.isExplodeRadio && tech.hasExplosiveDamageCheck()
+ },
+ requires: "an explosive damage source, not iridium-192",
+ effect: () => {
+ tech.explosiveRadius += 0.27;
+ },
+ remove() {
+ tech.explosiveRadius = 1;
+ }
+ },
+ {
+ name: "nitroglycerin",
+ description: "increase explosive damage by 66%
decrease explosive radius by 33%",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return !tech.isExplodeRadio && tech.hasExplosiveDamageCheck()
+ },
+ requires: "an explosive damage source, not iridium-192",
+ effect: () => {
+ tech.isSmallExplosion = true;
+ },
+ remove() {
+ tech.isSmallExplosion = false;
+ }
+ },
+ {
+ name: "acetone peroxide",
+ description: "increase explosive radius by 80%, but
you take 200% more harm from explosions",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ isBadRandomOption: true,
+ allowed() {
+ return tech.hasExplosiveDamageCheck()
+ },
+ requires: "an explosive damage source",
+ effect: () => {
+ tech.isExplosionHarm = true;
+ },
+ remove() {
+ tech.isExplosionHarm = false;
+ }
+ },
+ {
+ name: "shock wave",
+ description: "explosions stun mobs for 1-2 seconds
decrease explosive damage by 30%",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isExplodeRadio && tech.hasExplosiveDamageCheck()
+ },
+ requires: "an explosive damage source, not iridium-192",
+ effect() {
+ tech.isExplosionStun = true;
+ },
+ remove() {
+ tech.isExplosionStun = false;
+ }
+ },
+ {
+ name: "controlled explosion",
+ description: `use ${powerUps.orb.research(3)} to dynamically reduce all
explosions until they do no harm`,
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return !tech.isImmuneExplosion && (build.isExperimentSelection || powerUps.research.count > 2) && (tech.haveGunCheck("missiles") || tech.isMissileField || tech.missileBotCount > 0 || tech.isIncendiary || tech.isPulseLaser || tech.isTokamak || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb))
+ },
+ requires: "an explosive damage source, not electric reactive armor",
+ effect: () => {
+ tech.isSmartRadius = true;
+ for (let i = 0; i < 3; i++) {
+ if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
+ }
+ },
+ remove() {
+ tech.isSmartRadius = false;
+ if (this.count > 0) powerUps.research.changeRerolls(3)
+ }
+ },
+ {
+ name: "electric reactive armor",
+ // description: "explosions do no harm
while your energy is above 98%",
+ description: "harm from explosions is passively reduced
by 5% for every 10 stored energy",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return !tech.isSmartRadius && !tech.isExplodeRadio && tech.hasExplosiveDamageCheck()
+ },
+ requires: "an explosive damage source, not iridium-192",
+ effect: () => {
+ tech.isImmuneExplosion = true;
+ },
+ remove() {
+ tech.isImmuneExplosion = false;
+ }
+ },
{
name: "MIRV",
description: "fire +1 missile and grenade
decrease explosion radius up to 10%",
@@ -4671,183 +4829,6 @@ const tech = {
tech.isRadioactiveResistance = false
}
},
- {
- name: "iridium-192",
- description: "explosions release gamma radiation
100% more damage, but over 4 seconds",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.explosiveRadius === 1 && !tech.isSmallExplosion && (tech.haveGunCheck("missiles") || tech.isIncendiary || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.isPulseLaser || tech.isMissileField || tech.boomBotCount > 1 || tech.isTokamak)
- },
- requires: "an explosive damage source, not ammonium nitrate or nitroglycerin",
- effect: () => {
- tech.isExplodeRadio = true; //iridium-192
- },
- remove() {
- tech.isExplodeRadio = false;
- }
- },
- {
- name: "ammonium nitrate",
- description: "increase explosive damage by 27%
increase explosive radius by 27%",
- isGunTech: true,
- maxCount: 9,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return !tech.isExplodeRadio && tech.hasExplosiveDamageCheck()
- },
- requires: "an explosive damage source, not iridium-192",
- effect: () => {
- tech.explosiveRadius += 0.27;
- },
- remove() {
- tech.explosiveRadius = 1;
- }
- },
- {
- name: "nitroglycerin",
- description: "increase explosive damage by 66%
decrease explosive radius by 33%",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return !tech.isExplodeRadio && tech.hasExplosiveDamageCheck()
- },
- requires: "an explosive damage source, not iridium-192",
- effect: () => {
- tech.isSmallExplosion = true;
- },
- remove() {
- tech.isSmallExplosion = false;
- }
- },
- {
- name: "acetone peroxide",
- description: "increase explosive radius by 80%, but
you take 200% more harm from explosions",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- isBadRandomOption: true,
- allowed() {
- return tech.hasExplosiveDamageCheck()
- },
- requires: "an explosive damage source",
- effect: () => {
- tech.isExplosionHarm = true;
- },
- remove() {
- tech.isExplosionHarm = false;
- }
- },
- {
- name: "shock wave",
- description: "explosions stun mobs for 1-2 seconds
decrease explosive damage by 30%",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return !tech.isExplodeRadio && tech.hasExplosiveDamageCheck()
- },
- requires: "an explosive damage source, not iridium-192",
- effect() {
- tech.isExplosionStun = true;
- },
- remove() {
- tech.isExplosionStun = false;
- }
- },
- {
- name: "controlled explosion",
- description: `use ${powerUps.orb.research(3)} to dynamically reduce all
explosions until they do no harm`,
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return !tech.isImmuneExplosion && (build.isExperimentSelection || powerUps.research.count > 2) && (tech.haveGunCheck("missiles") || tech.isMissileField || tech.missileBotCount > 0 || tech.isIncendiary || tech.isPulseLaser || tech.isTokamak || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb))
- },
- requires: "an explosive damage source, not electric reactive armor",
- effect: () => {
- tech.isSmartRadius = true;
- for (let i = 0; i < 3; i++) {
- if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
- }
- },
- remove() {
- tech.isSmartRadius = false;
- if (this.count > 0) powerUps.research.changeRerolls(3)
- }
- },
- {
- name: "electric reactive armor",
- // description: "explosions do no harm
while your energy is above 98%",
- description: "harm from explosions is passively reduced
by 5% for every 10 stored energy",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return !tech.isSmartRadius && !tech.isExplodeRadio && tech.hasExplosiveDamageCheck()
- },
- requires: "an explosive damage source, not iridium-192",
- effect: () => {
- tech.isImmuneExplosion = true;
- },
- remove() {
- tech.isImmuneExplosion = false;
- }
- },
- {
- name: "incendiary ammunition",
- description: "shotgun, super balls, and drones
are loaded with explosives",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return ((m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && !(tech.isDroneTeleport || tech.isDroneRadioactive || tech.isSporeField || tech.isMissileField || tech.isIceField)) || (tech.haveGunCheck("drones") && !tech.isForeverDrones && !tech.isDroneRadioactive && !tech.isDroneTeleport) || tech.haveGunCheck("super balls") || tech.haveGunCheck("shotgun")) && !tech.isNailShot && !tech.isIceShot && !tech.isFoamShot && !tech.isWormShot && !tech.isNeedleShot
- },
- requires: "super balls, basic or slug shotgun, drones, not irradiated drones or burst drones",
- effect() {
- tech.isIncendiary = true
- },
- remove() {
- tech.isIncendiary = false;
- }
- },
- {
- name: "fragmentation",
- description: "some detonations and collisions eject nails
blocks, grenades, missiles, slugs, harpoon",
- isGunTech: true,
- maxCount: 9,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return tech.haveGunCheck("harpoon") || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.haveGunCheck("missiles") || tech.missileBotCount || (tech.haveGunCheck("shotgun") && tech.isSlugShot) || tech.blockDamage > 0.075
- },
- requires: "grenades, missiles, shotgun slugs, harpoon, or mass driver",
- effect() {
- tech.fragments++
- },
- remove() {
- tech.fragments = 0
- }
- },
{
name: "booby trap",
description: "drop a mine after picking up a power up
+53% JUNK to the potential tech pool",
@@ -5108,41 +5089,6 @@ const tech = {
tech.isBulletsLastLonger = 1;
}
},
- {
- name: "fault tolerance",
- description: "spawn 8 drones that last forever
remove your drone gun",
- isGunTech: true,
- isRemoveGun: true,
- maxCount: 1,
- count: 0,
- frequency: 1,
- frequencyDefault: 1,
- allowed() {
- return tech.haveGunCheck("drones", false) && !tech.isDroneRespawn && tech.isBulletsLastLonger === 1
- },
- requires: "drones, not drone repair, anti-shear topology",
- effect() {
- const num = 8
- tech.isForeverDrones += num
- if (tech.haveGunCheck("drones", false)) b.removeGun("drones")
- //spawn drones
- if (tech.isDroneRadioactive) {
- for (let i = 0; i < num * 0.25; i++) {
- b.droneRadioactive({ x: m.pos.x + 30 * (Math.random() - 0.5), y: m.pos.y + 30 * (Math.random() - 0.5) }, 5)
- bullet[bullet.length - 1].endCycle = Infinity
- }
- } else {
- for (let i = 0; i < num; i++) {
- b.drone({ x: m.pos.x + 30 * (Math.random() - 0.5), y: m.pos.y + 30 * (Math.random() - 0.5) }, 5)
- bullet[bullet.length - 1].endCycle = Infinity
- }
- }
- },
- remove() {
- tech.isForeverDrones = 0
- if (this.count && !tech.haveGunCheck("drones", false)) b.giveGuns("drones")
- }
- },
{
name: "reduced tolerances",
link: `reduced tolerances`,
@@ -5328,23 +5274,71 @@ const tech = {
}
},
{
- name: "capacitor bank",
- // description: "charge effects build up almost instantly
throwing blocks, foam, railgun, pulse, tokamak",
- descriptionFunction() { return `charge effects build up almost instantly
throwing blocks, ${tech.haveGunCheck("foam", false) ? "foam" : "foam"}, ${tech.haveGunCheck("harpoon", false) ? "railgun" : "railgun"}, ${tech.isPulseLaser ? "pulse" : "pulse"}, ${tech.isTokamak ? "tokamak" : "tokamak"}` },
+ name: "fault tolerance",
+ description: "spawn 8 drones that last forever
remove your drone gun",
isGunTech: true,
+ isRemoveGun: true,
maxCount: 1,
count: 0,
- frequency: 2,
- frequencyDefault: 2,
+ frequency: 1,
+ frequencyDefault: 1,
allowed() {
- return tech.blockDamage > 0.075 || tech.haveGunCheck("foam") || tech.isTokamak || tech.isPulseLaser
+ return tech.haveGunCheck("drones", false) && !tech.isDroneRespawn && tech.isBulletsLastLonger === 1
},
- requires: "throwing blocks, foam, pulse, tokamak",
+ requires: "drones, not drone repair, anti-shear topology",
effect() {
- tech.isCapacitor = true;
+ const num = 8
+ tech.isForeverDrones += num
+ if (tech.haveGunCheck("drones", false)) b.removeGun("drones")
+ //spawn drones
+ if (tech.isDroneRadioactive) {
+ for (let i = 0; i < num * 0.25; i++) {
+ b.droneRadioactive({ x: m.pos.x + 30 * (Math.random() - 0.5), y: m.pos.y + 30 * (Math.random() - 0.5) }, 5)
+ bullet[bullet.length - 1].endCycle = Infinity
+ }
+ } else {
+ for (let i = 0; i < num; i++) {
+ b.drone({ x: m.pos.x + 30 * (Math.random() - 0.5), y: m.pos.y + 30 * (Math.random() - 0.5) }, 5)
+ bullet[bullet.length - 1].endCycle = Infinity
+ }
+ }
},
remove() {
- tech.isCapacitor = false;
+ tech.isForeverDrones = 0
+ if (this.count && !tech.haveGunCheck("drones", false)) b.giveGuns("drones")
+ }
+ },
+ {
+ name: "surfactant",
+ description: "trade your foam gun for 2 foam-bots
and upgrade all bots to foam
",
+ isGunTech: true,
+ isRemoveGun: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isBot: true,
+ isBotTech: true,
+ isNonRefundable: true,
+ requires: "foam gun, NOT EXPERIMENT MODE, bot upgrades, fractionation, quantum foam",
+ allowed() {
+ return tech.haveGunCheck("foam", false) && !b.hasBotUpgrade() && !tech.isAmmoFoamSize && !tech.foamFutureFire
+ },
+ effect() {
+ tech.giveTech("foam-bot upgrade")
+ for (let i = 0; i < 2; i++) {
+ b.foamBot()
+ tech.foamBotCount++;
+ }
+ simulation.makeTextLog(`tech.isFoamBotUpgrade = true`)
+ if (tech.haveGunCheck("foam", false)) b.removeGun("foam")
+ },
+ remove() {
+ // if (this.count) {
+ // b.clearPermanentBots();
+ // b.respawnBots();
+ // if (!tech.haveGunCheck("foam")) b.giveGuns("foam")
+ // }
}
},
{
@@ -5464,152 +5458,63 @@ const tech = {
}
},
{
- name: "surfactant",
- description: "trade your foam gun for 2 foam-bots
and upgrade all bots to foam
",
+ name: "capacitor bank",
+ // description: "charge effects build up almost instantly
throwing blocks, foam, railgun, pulse, tokamak",
+ descriptionFunction() { return `charge effects build up almost instantly
throwing blocks, ${tech.haveGunCheck("foam", false) ? "foam" : "foam"}, ${tech.isRailGun ? "railgun" : "railgun"}, ${tech.isPulseLaser ? "pulse" : "pulse"}, ${tech.isTokamak ? "tokamak" : "tokamak"}` },
isGunTech: true,
- isRemoveGun: true,
maxCount: 1,
count: 0,
- frequency: 1,
- frequencyDefault: 1,
- isBot: true,
- isBotTech: true,
- isNonRefundable: true,
- requires: "foam gun, NOT EXPERIMENT MODE, bot upgrades, fractionation, quantum foam",
+ frequency: 2,
+ frequencyDefault: 2,
allowed() {
- return tech.haveGunCheck("foam", false) && !b.hasBotUpgrade() && !tech.isAmmoFoamSize && !tech.foamFutureFire
+ return tech.blockDamage > 0.075 || tech.isRailGun || tech.haveGunCheck("foam") || tech.isTokamak || tech.isPulseLaser
},
+ requires: "throwing blocks, railgun, foam, pulse, tokamak",
effect() {
- tech.giveTech("foam-bot upgrade")
- for (let i = 0; i < 2; i++) {
- b.foamBot()
- tech.foamBotCount++;
+ tech.isCapacitor = true;
+ },
+ remove() {
+ tech.isCapacitor = false;
+ }
+ },
+ {
+ name: "railgun",
+ description: `harpoons are 66% denser, but don't retract
gain 600% more harpoon ammo per ${powerUps.orb.ammo(1)}`,
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("harpoon") && !tech.isFilament && !tech.extraHarpoons && !tech.isHarpoonPowerUp
+ },
+ requires: "harpoon, not filament, reticulum, toggling harpoon",
+ ammoBonus: 6,
+ effect() {
+ tech.isRailGun = true;
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "harpoon") {
+ b.guns[i].chooseFireMethod()
+ b.guns[i].ammoPack = this.ammoBonus;
+ b.guns[i].ammo = b.guns[i].ammo * this.ammoBonus;
+ simulation.updateGunHUD();
+ break
+ }
}
- simulation.makeTextLog(`tech.isFoamBotUpgrade = true`)
- if (tech.haveGunCheck("foam", false)) b.removeGun("foam")
},
remove() {
- // if (this.count) {
- // b.clearPermanentBots();
- // b.respawnBots();
- // if (!tech.haveGunCheck("foam")) b.giveGuns("foam")
- // }
- }
- },
- {
- name: "filament",
- description: "increase the length of your harpoon's rope
by 1% per harpoon ammo",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("harpoon")
- },
- requires: "harpoon",
- effect() {
- tech.isFilament = true;
- },
- remove() {
- tech.isFilament = false;
- }
- },
- {
- name: "unaaq",
- link: `unaaq`, //https://en.wikipedia.org/wiki/Weapon
- description: "increase the size of your harpoon
by 10% of the square root of harpoon ammo",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("harpoon")
- },
- requires: "harpoon",
- effect() {
- tech.isLargeHarpoon = true;
- },
- remove() {
- tech.isLargeHarpoon = false;
- }
- },
- {
- name: "toggling harpoon",
- description: "increase the damage of your next harpoon
by 600% after using it to collect a power up",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("harpoon")
- },
- requires: "harpoon",
- effect() {
- tech.isHarpoonPowerUp = true
- },
- remove() {
- tech.isHarpoonPowerUp = false
- tech.harpoonDensity = 0.008
- }
- },
- {
- name: "reticulum",
- description: "fire +1 harpoon, but energy cost
to retract also increases",
- isGunTech: true,
- maxCount: 9,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("harpoon")
- },
- requires: "harpoon",
- effect() {
- tech.extraHarpoons++;
- },
- remove() {
- tech.extraHarpoons = 0;
- }
- },
- // {
- // name: "railgun",
- // description: "firing the harpoon while crouched launches
a rod that is faster, larger, and more dense",
- // isGunTech: true,
- // maxCount: 1,
- // count: 0,
- // frequency: 2,
- // frequencyDefault: 2,
- // allowed() {
- // return tech.haveGunCheck("harpoon")
- // },
- // requires: "railgun",
- // effect() {
- // tech.isRailGun = true;
- // },
- // remove() {
- // tech.isRailGun = false;
- // }
- // },
- {
- name: "half-wave rectifier",
- description: "harpoons drain no energy as they retract
crouch firing harpoon generates energy",
- isGunTech: true,
- maxCount: 1,
- count: 0,
- frequency: 2,
- frequencyDefault: 2,
- allowed() {
- return tech.haveGunCheck("harpoon")
- },
- requires: "railgun",
- effect() {
- tech.isRailEnergyGain = true;
- },
- remove() {
- tech.isRailEnergyGain = false;
+ if (tech.isRailGun) {
+ tech.isRailGun = false;
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "harpoon") {
+ b.guns[i].chooseFireMethod()
+ b.guns[i].ammoPack = 0.6;
+ b.guns[i].ammo = Math.ceil(b.guns[i].ammo / this.ammoBonus);
+ simulation.updateGunHUD();
+ break
+ }
+ }
+ }
}
},
// {
@@ -5650,6 +5555,122 @@ const tech = {
// tech.isRodAreaDamage = false;
// }
// },
+ {
+ name: "half-wave rectifier",
+ description: "harpoons drain no energy as they retract
crouch firing harpoon generates energy",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("harpoon")
+ },
+ requires: "railgun",
+ effect() {
+ tech.isRailEnergyGain = true;
+ },
+ remove() {
+ tech.isRailEnergyGain = false;
+ }
+ },
+ {
+ name: "ceramics",
+ description: `needles and harpoons pierce shields
directly damaging shielded mobs`,
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("harpoon") || (tech.isNeedles || tech.isNeedleShot)
+ },
+ requires: "nail gun, needle gun, needle-shot, harpoon",
+ effect() {
+ tech.isShieldPierce = true
+ },
+ remove() {
+ tech.isShieldPierce = false
+ }
+ },
+ {
+ name: "unaaq",
+ link: `unaaq`, //https://en.wikipedia.org/wiki/Weapon
+ description: "increase the size of your harpoon
by 10% of the square root of harpoon ammo",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("harpoon")
+ },
+ requires: "harpoon",
+ effect() {
+ tech.isLargeHarpoon = true;
+ },
+ remove() {
+ tech.isLargeHarpoon = false;
+ }
+ },
+ {
+ name: "filament",
+ description: "increase the length of your harpoon's rope
by 1% per harpoon ammo",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("harpoon") && !tech.isRailGun
+ },
+ requires: "harpoon",
+ effect() {
+ tech.isFilament = true;
+ },
+ remove() {
+ tech.isFilament = false;
+ }
+ },
+ {
+ name: "toggling harpoon",
+ description: "increase the damage of your next harpoon
by 600% after using it to collect a power up",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("harpoon") && !tech.isRailGun
+ },
+ requires: "harpoon",
+ effect() {
+ tech.isHarpoonPowerUp = true
+ },
+ remove() {
+ tech.isHarpoonPowerUp = false
+ tech.harpoonDensity = 0.006
+ }
+ },
+ {
+ name: "reticulum",
+ description: "fire +1 harpoon, but energy cost
to retract also increases",
+ isGunTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("harpoon") && !tech.isRailGun
+ },
+ requires: "harpoon",
+ effect() {
+ tech.extraHarpoons++;
+ },
+ remove() {
+ tech.extraHarpoons = 0;
+ }
+ },
{
name: "optical amplifier",
description: "gain 3 random laser guntech
laser only turns off if you have no energy",
@@ -6954,7 +6975,7 @@ const tech = {
},
{
name: "virtual particles",
- description: `use ${powerUps.orb.research(4)}to exploit your wormhole for a
13% chance to duplicate spawned power ups`,
+ description: `use ${powerUps.orb.research(4)}to exploit your wormhole for a
12% chance to duplicate spawned power ups`,
isFieldTech: true,
maxCount: 1,
count: 0,
@@ -6965,7 +6986,7 @@ const tech = {
},
requires: "wormhole",
effect() {
- tech.wormDuplicate = 0.13
+ tech.wormDuplicate = 0.12
powerUps.setDupChance(); //needed after adjusting duplication chance
if (!build.isExperimentSelection && !simulation.isTextLogOpen) simulation.circleFlare(0.13);
for (let i = 0; i < 4; i++) {
@@ -6980,7 +7001,7 @@ const tech = {
},
{
name: "Penrose process",
- description: "after a block falls into a wormhole
you gain 63 energy",
+ description: "after a block falls into a wormhole
you gain 53 energy",
isFieldTech: true,
maxCount: 1,
count: 0,
@@ -9309,4 +9330,5 @@ const tech = {
extraSuperBalls: null,
isTimeCrystals: null,
isGroundState: null,
+ isRailGun: null
}
\ No newline at end of file
diff --git a/todo.txt b/todo.txt
index 530b9fe..bb9cea6 100644
--- a/todo.txt
+++ b/todo.txt
@@ -1,29 +1,47 @@
******************************************************** NEXT PATCH **************************************************
-new reactor boss - mineBoss
- 1/3 chance for 1 of 3 different bosses to spawn on the reactor level
+tech railgun - harpoon charge fires and no longer retracts, get 8x ammo from power ups
+ railgun has auto-targeting, like harpoon
+ the aiming graphic is gone
+ disables filament, reticulum, toggling
+ unlocks capacitor bank
-harpoon starts with 10->3 ammo, and still gets 1 ammo per powerUpx
-network effect damage per bot 7->6%
-perimeter defense harm reduction 8->7%
+mobs do 2% less harm to player
+player does 0.5% more damage per level
+Zeno's paradox removes 1/10 -> 1/12 -> 1/14 (7%) health every 5 seconds
+drone gun gets 10% more ammo
-bug fix decoherence
+harpoon damage reduced by 15%
+random bots have a 100% -> 66% chance to match your upgraded bot type
+phonon has 1/8 -> 1/9 less ammo than matter wave
+Penrose process gain 63 -> 53 energy when wormhole eats blocks
+transdimensional spores makes 20% fewer spores when wormhole eats blocks
+
+bugfixes
******************************************************** TODO ********************************************************
+tech: when this tech is ejected spawn one of every power up type
+ JUNK tech?
+
+railgun feels like a downgrade from harpoon
+ buff railgun
+ increase harpoon size
+ nerf harpoon
+ shrink crouch mode harpoon size
+
+
+try to get grappling hook working again
+
+bug - does any url sharing work?
+
+setting to remove UI, except health bar
+ except active gun? to see ammo
+ checkbox in pause and in settings
+
+damage for each different bot type you have
disables bot upgrades?
-improve rail gun / use ammo to crouch fire style for harpoon
- spend ammo to get some tech
- ammo cost on reticulum
- spend ammo to make harpoon radioactive
- tech disables filament and unaaq? probably don't need to
- give rail gun the auto targeting
- improve auto-target with a tech?
- you already tried this and target probably can't get better
- try to get grappling hook working again
-
tech doing damage refunds up to 50% of damage take in last 10 seconds
use history[] to manage this?
@@ -42,7 +60,9 @@ make a seed/hash system that controls only the tech/guns/fields shown
tech upgrade to anthropic principle to make it trigger at 50% life and 0% once per map
-JUNK tech: https://bindingofisaacrebirth.fandom.com/wiki/Damocles
+tech: spontaneous collapse - very low chance of something to occur
+ JUNK tech
+ https://bindingofisaacrebirth.fandom.com/wiki/Damocles
cloaking field doesn't show energy over max