grappling hook

tech grappling hook - can attack to walls and pull you towards the walls
   harpoon extends farther as you hold down fire, but no longer has auto-steering

mobs do 4% less harm per difficulty level
railgun/harpoon auto-targeting is smarter at long distances with multiple small targets
  but it still has trouble with moving targets
booby trap only has a 100 -> 50% chance to drop a mine when picking up power ups
added fallback for browsers that don't allow local storage
This commit is contained in:
landgreen
2022-02-24 05:50:39 -08:00
parent e73abc63ba
commit 1ca00d3598
9 changed files with 608 additions and 222 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@@ -1348,6 +1348,285 @@ const b = {
Composite.add(engine.world, bullet[me]); //add bullet to world Composite.add(engine.world, bullet[me]); //add bullet to world
}, },
grapple(where, angle = m.angle, isReturn = false, harpoonSize = 1) {
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 }], {
cycle: 0,
angle: angle,
friction: 1,
frictionAir: 0.4,
thrustMag: 0.1,
dmg: 6, //damage done in addition to the damage from momentum
classType: "bullet",
endCycle: simulation.cycle + 45,
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: 4,
ropeExtension: 0,
lookFrequency: Math.floor(7 + Math.random() * 3),
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
requestAnimationFrame(() => { who.isShielded = true });
}
if (tech.fragments) {
b.targetedNail(this.vertices[2], tech.fragments * 3)
if (!isReturn) this.endCycle = 0;
}
if (!who.isBadTarget) {
if (isReturn) {
this.do = this.returnToPlayer
} else {
this.frictionAir = 0.01
this.do = () => {
this.force.y += this.mass * 0.003; //gravity
this.draw();
}
}
}
},
caughtPowerUp: null,
dropCaughtPowerUp() {
if (this.caughtPowerUp) {
this.caughtPowerUp.collisionFilter.category = cat.powerUp
this.caughtPowerUp.collisionFilter.mask = cat.map | cat.powerUp
this.caughtPowerUp = null
}
},
onEnd() {
if (this.caughtPowerUp && !simulation.isChoosing && (this.caughtPowerUp.name !== "heal" || m.health !== m.maxHealth || tech.isOverHeal)) {
let index = null //find index
for (let i = 0, len = powerUp.length; i < len; ++i) {
if (powerUp[i] === this.caughtPowerUp) index = i
}
if (index !== null) {
powerUps.onPickUp(this.caughtPowerUp);
this.caughtPowerUp.effect();
Matter.Composite.remove(engine.world, this.caughtPowerUp);
powerUp.splice(index, 1);
if (tech.isHarpoonPowerUp) tech.harpoonDensity = 0.006 * 6 //0.006 is normal
} else {
this.dropCaughtPowerUp()
}
} else {
this.dropCaughtPowerUp()
}
},
drawString() {
const where = {
x: m.pos.x + 30 * Math.cos(m.angle),
y: m.pos.y + 30 * Math.sin(m.angle)
}
const sub = Vector.sub(where, this.vertices[0])
const controlPoint = Vector.add(where, Vector.mult(sub, -0.5))
ctx.strokeStyle = "#000" // "#0ce"
ctx.lineWidth = 0.5
ctx.beginPath();
ctx.moveTo(where.x, where.y);
ctx.quadraticCurveTo(controlPoint.x, controlPoint.y, this.vertices[0].x, this.vertices[0].y)
// ctx.lineTo(this.vertices[0].x, this.vertices[0].y);
ctx.stroke();
},
draw() {},
returnToPlayer() {
if (Vector.magnitude(Vector.sub(this.position, m.pos)) < returnRadius) { //near player
this.endCycle = 0;
if (m.cycle + 25 * b.fireCDscale < m.fireCDcycle) m.fireCDcycle = m.cycle + 35 * b.fireCDscale //lower cd to 25 if it is above 25
//recoil on catching
const momentum = Vector.mult(Vector.sub(this.velocity, player.velocity), (input.down ? 0.00015 : 0.0003))
player.force.x += momentum.x
player.force.y += momentum.y
// refund ammo
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "harpoon") {
b.guns[i].ammo++;
simulation.updateGunHUD();
break;
}
}
} else {
if (!tech.isRailEnergyGain && m.energy > 0.005) m.energy -= 0.005
const sub = Vector.sub(this.position, m.pos)
const rangeScale = 1 + 0.000001 * Vector.magnitude(sub) * Vector.magnitude(sub) //return faster when far from player
const returnForce = Vector.mult(Vector.normalise(sub), rangeScale * this.thrustMag * this.mass)
this.force.x -= returnForce.x
this.force.y -= returnForce.y
this.grabPowerUp()
}
this.draw();
},
grabPowerUp() { //grab power ups near the tip of the harpoon
if (this.caughtPowerUp) {
Matter.Body.setPosition(this.caughtPowerUp, Vector.add(this.vertices[2], this.velocity))
Matter.Body.setVelocity(this.caughtPowerUp, { x: 0, y: 0 })
} else { //&& simulation.cycle % 2
for (let i = 0, len = powerUp.length; i < len; ++i) {
const radius = powerUp[i].circleRadius + 50
if (Vector.magnitudeSquared(Vector.sub(this.vertices[2], powerUp[i].position)) < radius * radius) {
if (powerUp[i].name !== "heal" || m.health !== m.maxHealth || tech.isOverHeal) {
this.caughtPowerUp = powerUp[i]
Matter.Body.setVelocity(powerUp[i], { x: 0, y: 0 })
Matter.Body.setPosition(powerUp[i], this.vertices[2])
powerUp[i].collisionFilter.category = 0
powerUp[i].collisionFilter.mask = 0
this.thrustMag *= 0.6
this.endCycle += 0.5 //it pulls back slower, so this prevents it from ending early
break //just pull 1 power up if possible
}
}
}
}
},
do() {
this.cycle++
if (isReturn) {
if (input.fire) {
this.grabPowerUp()
if (this.endCycle < simulation.cycle + 1) { //if at end of lifespan, but player is holding down fire, force retraction
this.endCycle = simulation.cycle + 60
m.fireCDcycle = m.cycle + 20 // cool down
this.do = this.returnToPlayer
Matter.Body.setDensity(this, 0.0005); //reduce density on return
if (this.angularSpeed < 0.5) this.torque += this.inertia * 0.001 * (Math.random() - 0.5) //(Math.round(Math.random()) ? 1 : -1)
this.collisionFilter.mask = cat.map | cat.mob | cat.mobBullet | cat.mobShield // | cat.body
}
} else {
//snap rope if not enough energy
if (m.energy < 0.05) {
const returnForce = Vector.mult(Vector.normalise(Vector.sub(this.position, m.pos)), 3 * this.thrustMag * this.mass)
this.force.x -= returnForce.x
this.force.y -= returnForce.y
this.frictionAir = 0.002
this.do = () => {
if (this.speed < 20) this.force.y += 0.0005 * this.mass;
}
this.dropCaughtPowerUp()
} else {
//return to player
this.do = this.returnToPlayer
this.endCycle = simulation.cycle + 60
Matter.Body.setDensity(this, 0.0005); //reduce density on return
if (this.angularSpeed < 0.5) this.torque += this.inertia * 0.001 * (Math.random() - 0.5) //(Math.round(Math.random()) ? 1 : -1)
this.collisionFilter.mask = cat.map | cat.mob | cat.mobBullet | cat.mobShield // | cat.body
}
}
//grappling hook
if (input.fire && Matter.Query.collides(this, map).length) {
const pull = Vector.mult(Vector.normalise(Vector.sub(this.position, m.pos)), 0.1)
player.force.x += pull.x
player.force.y += pull.y - player.mass * 0.02
const move = { x: 50 * Math.cos(this.angle), y: 50 * Math.sin(this.angle), }
Matter.Body.setPosition(this, Vector.add(this.position, move))
if (Matter.Query.collides(this, map).length) {
Matter.Body.setStatic(this, true)
this.endCycle = simulation.cycle + 5
this.dropCaughtPowerUp()
this.do = () => {
// const grappleBack = {
// x: this.position.x - 50 * Math.cos(this.angle),
// y: this.position.y - 50 * Math.sin(this.angle)
// }
//between player nose and the grapple
const sub = Vector.sub(this.vertices[0], {
x: m.pos.x + 30 * Math.cos(m.angle),
y: m.pos.y + 30 * Math.sin(m.angle)
})
let dist = Vector.magnitude(sub) - this.ropeExtension
if (input.fire) {
m.fireCDcycle = m.cycle + 30; // cool down if out of energy
this.endCycle = simulation.cycle + 10
Matter.Body.setVelocity(player, { x: player.velocity.x * 0.8, y: player.velocity.y * 0.8 });
if (input.down) { //down
dist *= 0.25
player.force.y += 5 * player.mass * simulation.g;
}
//control position while hooked
// if (input.down) { //down
// player.force.y += 5 * player.mass * simulation.g;
// dist *= 0.25
// this.ropeExtension += 10
// } else if (input.up) { //up
// this.ropeExtension -= 10
// if (this.ropeExtension < 0) this.ropeExtension = 0
// player.force.y -= 5 * player.mass * simulation.g;
// dist *= 0.4
// } else {}
// if (input.right) { //down
// dist *= 0.4
// player.force.x += 5 * player.mass * simulation.g;
// } else if (input.left) { //up
// dist *= 0.4
// player.force.x -= 5 * player.mass * simulation.g;
// }
if (!tech.isRailEnergyGain && m.energy > 0.004 && dist > 400) m.energy -= 0.004
const pull = Vector.mult(Vector.normalise(sub), 0.00035 * Math.min(Math.max(30, dist), 500))
player.force.x += pull.x
player.force.y += pull.y
} else { //if (Vector.magnitude(Vector.sub(this.position, m.pos)) < returnRadius + 200)
// if (input.up) { //up
// player.force.y -= 20 * player.mass * simulation.g;
// }
//automatically get ammo back
this.endCycle = 0;
if (m.cycle + 15 * b.fireCDscale < m.fireCDcycle) m.fireCDcycle = m.cycle + 15 * b.fireCDscale //lower cd to 15 if it is above 15
// refund ammo
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "harpoon") {
b.guns[i].ammo++;
simulation.updateGunHUD();
break;
}
}
}
// if (dist > returnRadius)
this.draw();
}
}
}
this.force.x += this.thrustMag * this.mass * Math.cos(this.angle);
this.force.y += this.thrustMag * this.mass * Math.sin(this.angle);
this.draw()
}
},
});
if (!isReturn) {
Matter.Body.setVelocity(bullet[me], {
x: m.Vx / 2 + 60 * Math.cos(bullet[me].angle),
y: m.Vy / 2 + 60 * Math.sin(bullet[me].angle)
});
bullet[me].frictionAir = 0.002
bullet[me].do = function() {
if (this.speed < 20) this.force.y += 0.0005 * this.mass;
this.draw();
}
}
if (tech.isHarpoonPowerUp && bullet[me].density > 0.01) {
if (isReturn) {
bullet[me].draw = function() {
this.drawToggleHarpoon()
this.drawString()
}
} else {
bullet[me].draw = function() {
this.drawToggleHarpoon()
}
}
} else if (isReturn) {
bullet[me].draw = function() {
this.drawString()
}
}
Composite.add(engine.world, bullet[me]); //add bullet to world
},
harpoon(where, target, angle = m.angle, harpoonSize = 1, isReturn = false, totalCycles = 35) { harpoon(where, target, angle = m.angle, harpoonSize = 1, isReturn = false, totalCycles = 35) {
const me = bullet.length; const me = bullet.length;
const returnRadius = 100 * Math.sqrt(harpoonSize) const returnRadius = 100 * Math.sqrt(harpoonSize)
@@ -1505,16 +1784,21 @@ const b = {
}, },
do() { do() {
this.cycle++ this.cycle++
if (isReturn || target) {
if (isReturn) { if (isReturn) {
if (this.cycle > totalCycles) { if (this.cycle > totalCycles) {
if (m.energy < 0.05) { //snap rope if not enough energy //snap rope if not enough energy
if (m.energy < 0.05) {
const returnForce = Vector.mult(Vector.normalise(Vector.sub(this.position, m.pos)), 3 * this.thrustMag * this.mass) const returnForce = Vector.mult(Vector.normalise(Vector.sub(this.position, m.pos)), 3 * this.thrustMag * this.mass)
this.force.x -= returnForce.x this.force.x -= returnForce.x
this.force.y -= returnForce.y this.force.y -= returnForce.y
this.frictionAir = 0.002 this.frictionAir = 0.002
this.do = () => { if (this.speed < 20) this.force.y += 0.0005 * this.mass; } this.do = () => {
if (this.speed < 20) this.force.y += 0.0005 * this.mass;
}
this.dropCaughtPowerUp() this.dropCaughtPowerUp()
} else { //return to player } else {
//return to player
this.do = this.returnToPlayer this.do = this.returnToPlayer
Matter.Body.setDensity(this, 0.0005); //reduce density on return Matter.Body.setDensity(this, 0.0005); //reduce density on return
if (this.angularSpeed < 0.5) this.torque += this.inertia * 0.001 * (Math.random() - 0.5) //(Math.round(Math.random()) ? 1 : -1) if (this.angularSpeed < 0.5) this.torque += this.inertia * 0.001 * (Math.random() - 0.5) //(Math.round(Math.random()) ? 1 : -1)
@@ -1523,9 +1807,6 @@ const b = {
} else { } else {
this.grabPowerUp() this.grabPowerUp()
} }
} else if (this.cycle > 30) {
this.frictionAir = 0.003
this.do = () => { if (this.speed < 20) this.force.y += 0.0005 * this.mass; }
} }
if (target) { //rotate towards the target if (target) { //rotate towards the target
@@ -1540,7 +1821,40 @@ const b = {
Matter.Body.rotate(this, -this.turnRate); Matter.Body.rotate(this, -this.turnRate);
} }
} }
if (isReturn || target) { //grappling hook
// if (input.fire && !input.down && Matter.Query.collides(this, map).length) {
// const pull = Vector.mult(Vector.normalise(Vector.sub(this.position, m.pos)), 0.1)
// player.force.x += pull.x
// player.force.y += pull.y - player.mass * 0.02
// Matter.Body.setStatic(this, true)
// this.endCycle = simulation.cycle + 5
// this.dropCaughtPowerUp()
// this.do = () => {
// const sub = Vector.sub(this.position, m.pos)
// const dist = Vector.magnitude(sub)
// if (input.fire) {
// m.fireCDcycle = m.cycle + 30; // cool down if out of energy
// this.endCycle = simulation.cycle + 10
// const pull = Vector.mult(Vector.normalise(sub), 0.001 * Math.min(Math.max(1, dist), 100))
// player.force.x += pull.x
// player.force.y += pull.y
// Matter.Body.setVelocity(player, { x: player.velocity.x * 0.8, y: player.velocity.y * 0.8 });
// } else { //if (Vector.magnitude(Vector.sub(this.position, m.pos)) < returnRadius + 200)
// //automatically get ammo back
// this.endCycle = 0;
// if (m.cycle + 15 * b.fireCDscale < m.fireCDcycle) m.fireCDcycle = m.cycle + 15 * b.fireCDscale //lower cd to 15 if it is above 15
// // refund ammo
// for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
// if (b.guns[i].name === "harpoon") {
// b.guns[i].ammo++;
// simulation.updateGunHUD();
// break;
// }
// }
// }
// if (dist > returnRadius) this.draw();
// }
// }
this.force.x += this.thrustMag * this.mass * Math.cos(this.angle); this.force.x += this.thrustMag * this.mass * Math.cos(this.angle);
this.force.y += this.thrustMag * this.mass * Math.sin(this.angle); this.force.y += this.thrustMag * this.mass * Math.sin(this.angle);
} }
@@ -2118,7 +2432,7 @@ const b = {
dmg: 0, // 0.14 //damage done in addition to the damage from momentum dmg: 0, // 0.14 //damage done in addition to the damage from momentum
minDmgSpeed: 2, minDmgSpeed: 2,
lookFrequency: 67 + Math.floor(7 * Math.random()), lookFrequency: 67 + Math.floor(7 * Math.random()),
drain: 0.62 * tech.isLaserDiode * tech.laserFieldDrain, drain: 0.7 * tech.isLaserDiode * tech.laserFieldDrain,
isDetonated: false, isDetonated: false,
torqueMagnitude: 0.000003 * (Math.round(Math.random()) ? 1 : -1), torqueMagnitude: 0.000003 * (Math.round(Math.random()) ? 1 : -1),
range: 1500, range: 1500,
@@ -5615,6 +5929,9 @@ const b = {
if (tech.isRailGun) { if (tech.isRailGun) {
this.do = this.railDo this.do = this.railDo
this.fire = this.railFire this.fire = this.railFire
} else if (tech.isGrapple) {
this.do = () => {}
this.fire = this.grappleFire
} else { } else {
this.do = () => {} this.do = () => {}
this.fire = this.harpoonFire this.fire = this.harpoonFire
@@ -5643,57 +5960,6 @@ const b = {
distance: 10000, distance: 10000,
target: null target: null
} }
const harpoonSize = tech.isLargeHarpoon ? 1 + 0.1 * Math.sqrt(this.ammo) : 1
if (tech.extraHarpoons) {
let targetCount = 0
const SPREAD = 0.06 + 0.05 * (!input.down)
let angle = m.angle - SPREAD * tech.extraHarpoons / 2;
const dir = { x: Math.cos(angle), y: Math.sin(angle) }; //make a vector for the player's direction of length 1; used in dot product
for (let i = 0, len = mob.length; i < len; ++i) {
if (mob[i].alive && !mob[i].isBadTarget && !mob[i].shield && 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
if (dot > 0.7) { //lower dot product threshold for targeting then if you only have one harpoon //target closest mob that player is looking at and isn't too close to target
if (this.ammo > 0) {
this.ammo--
b.harpoon(where, mob[i], angle, harpoonSize, false) //Vector.angle(Vector.sub(where, mob[i].position), { x: 0, y: 0 })
angle += SPREAD
targetCount++
if (targetCount > tech.extraHarpoons) break
}
}
}
}
//if more harpoons and no targets left
if (targetCount < tech.extraHarpoons + 1) {
const num = tech.extraHarpoons + 1 - targetCount
for (let i = 0; i < num; i++) {
if (this.ammo > 0) {
this.ammo--
b.harpoon(where, null, angle, harpoonSize, false)
angle += SPREAD
}
}
}
this.ammo++ //make up for the ammo used up in fire()
simulation.updateGunHUD();
} else {
//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
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]
}
}
}
b.harpoon(where, closest.target, m.angle, harpoonSize, false)
}
//push away blocks and mobs //push away blocks and mobs
const range = 1200 * this.charge const range = 1200 * this.charge
for (let i = 0, len = mob.length; i < len; ++i) { //push away mobs when firing for (let i = 0, len = mob.length; i < len; ++i) { //push away mobs when firing
@@ -5731,6 +5997,57 @@ const b = {
player.force.x -= recoil.x player.force.x -= recoil.x
player.force.y -= recoil.y 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 tech.harpoonDensity = 0.006 //0.001 is normal for blocks, 0.006 is normal for harpoon, 0.006*6 when buffed
const harpoonSize = tech.isLargeHarpoon ? 1 + 0.1 * Math.sqrt(this.ammo) : 1
if (tech.extraHarpoons) {
let targetCount = 0
const SPREAD = 0.06 + 0.05 * (!input.down)
let angle = m.angle - SPREAD * tech.extraHarpoons / 2;
const dir = { x: Math.cos(angle), y: Math.sin(angle) }; //make a vector for the player's direction of length 1; used in dot product
for (let i = 0, len = mob.length; i < len; ++i) {
if (mob[i].alive && !mob[i].isBadTarget && !mob[i].shield && 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))
// console.log(dot, 0.95 - Math.min(dist * 0.00015, 0.3))
if (dot > 0.95 - Math.min(dist * 0.00015, 0.3)) { //lower dot product threshold for targeting then if you only have one harpoon //target closest mob that player is looking at and isn't too close to target
if (this.ammo > -1) {
this.ammo--
b.harpoon(where, mob[i], angle, harpoonSize, false) //Vector.angle(Vector.sub(where, mob[i].position), { x: 0, y: 0 })
angle += SPREAD
targetCount++
if (targetCount > tech.extraHarpoons) break
}
}
}
}
//if more harpoons and no targets left
if (targetCount < tech.extraHarpoons + 1) {
const num = tech.extraHarpoons + 1 - targetCount
for (let i = 0; i < num; i++) {
if (this.ammo > -1) {
this.ammo--
b.harpoon(where, null, angle, harpoonSize, false)
angle += SPREAD
}
}
}
this.ammo++ //make up for the ammo used up in fire()
simulation.updateGunHUD();
} else {
//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
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.98 - Math.min(dist * 0.00014, 0.3)) { //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)
}
this.charge = 0; this.charge = 0;
} else { //charging } else { //charging
@@ -5784,6 +6101,31 @@ const b = {
m.fireCDcycle = m.cycle + 10 //can't fire until mouse is released m.fireCDcycle = m.cycle + 10 //can't fire until mouse is released
this.charge += 0.00001 this.charge += 0.00001
}, },
grappleFire() {
const where = {
x: m.pos.x + 30 * Math.cos(m.angle),
y: m.pos.y + 30 * Math.sin(m.angle)
}
const harpoonSize = (tech.isLargeHarpoon ? 1 + 0.1 * Math.sqrt(this.ammo) : 1) //* (input.down ? 0.7 : 1)
if (tech.extraHarpoons && !input.down) { //multiple harpoons
const SPREAD = 0.06
const len = tech.extraHarpoons + 1
let angle = m.angle - SPREAD * len / 2;
for (let i = 0; i < len; i++) {
if (this.ammo > 0) {
this.ammo--
b.grapple(where, angle, true, harpoonSize)
angle += SPREAD
}
}
this.ammo++ //make up for the ammo used up in fire()
simulation.updateGunHUD();
m.fireCDcycle = m.cycle + 90 // cool down
} else {
b.grapple(where, m.angle, !input.down, harpoonSize)
}
m.fireCDcycle = m.cycle + 45 // cool down
},
harpoonFire() { harpoonFire() {
const where = { const where = {
x: m.pos.x + 30 * Math.cos(m.angle), x: m.pos.x + 30 * Math.cos(m.angle),
@@ -5796,18 +6138,18 @@ const b = {
//look for closest mob in player's LoS //look for closest mob in player's LoS
const harpoonSize = (tech.isLargeHarpoon ? 1 + 0.1 * Math.sqrt(this.ammo) : 1) //* (input.down ? 0.7 : 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) const totalCycles = 7 * (tech.isFilament ? 1 + 0.01 * Math.min(110, this.ammo) : 1) * Math.sqrt(harpoonSize)
if (tech.extraHarpoons && !input.down) { //multiple harpoons
const SPREAD = 0.1 const SPREAD = 0.1
let angle = m.angle - SPREAD * tech.extraHarpoons / 2; let angle = m.angle - SPREAD * tech.extraHarpoons / 2;
const dir = { x: Math.cos(angle), y: Math.sin(angle) }; //make a vector for the player's direction of length 1; used in dot product const dir = { x: Math.cos(angle), y: Math.sin(angle) }; //make a vector for the player's direction of length 1; used in dot product
if (tech.extraHarpoons && !input.down) {
const range = 450 * (tech.isFilament ? 1 + 0.005 * Math.min(110, this.ammo) : 1) const range = 450 * (tech.isFilament ? 1 + 0.005 * Math.min(110, this.ammo) : 1)
let targetCount = 0 let targetCount = 0
for (let i = 0, len = mob.length; i < len; ++i) { for (let i = 0, len = mob.length; i < len; ++i) {
if (mob[i].alive && !mob[i].isBadTarget && !mob[i].shield && Matter.Query.ray(map, m.pos, mob[i].position).length === 0) { if (mob[i].alive && !mob[i].isBadTarget && !mob[i].shield && 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 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)) const dist = Vector.magnitude(Vector.sub(where, mob[i].position))
if (dist < range && dot > 0.7) { //lower dot product threshold for targeting then if you only have one harpoon //target closest mob that player is looking at and isn't too close to target if (dist < range && dot > 0.9) { //lower dot product threshold for targeting then if you only have one harpoon //target closest mob that player is looking at and isn't too close to target
if (this.ammo > 0) { if (this.ammo > 0) {
this.ammo-- this.ammo--
b.harpoon(where, mob[i], angle, harpoonSize, true, totalCycles) //Vector.angle(Vector.sub(where, mob[i].position), { x: 0, y: 0 }) b.harpoon(where, mob[i], angle, harpoonSize, true, totalCycles) //Vector.angle(Vector.sub(where, mob[i].position), { x: 0, y: 0 })
@@ -5833,17 +6175,23 @@ const b = {
simulation.updateGunHUD(); simulation.updateGunHUD();
m.fireCDcycle = m.cycle + 90 // cool down m.fireCDcycle = m.cycle + 90 // cool down
} else { } else {
//single harpoon
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
for (let i = 0, len = mob.length; i < len; ++i) { 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) { 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 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)) 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 if (dist < closest.distance && dot > 0.98 - Math.min(dist * 0.00014, 0.3)) { //target closest mob that player is looking at and isn't too close to target
closest.distance = dist closest.distance = dist
closest.target = mob[i] closest.target = mob[i]
} }
} }
} }
b.harpoon(where, closest.target, m.angle, harpoonSize, !input.down, totalCycles) if (input.down) {
b.harpoon(where, closest.target, m.angle, harpoonSize, false, 70)
} else {
b.harpoon(where, closest.target, m.angle, harpoonSize, true, totalCycles)
}
m.fireCDcycle = m.cycle + 45 // cool down m.fireCDcycle = m.cycle + 45 // cool down
} }
const recoil = Vector.mult(Vector.normalise(Vector.sub(where, m.pos)), input.down ? 0.015 : 0.035) const recoil = Vector.mult(Vector.normalise(Vector.sub(where, m.pos)), input.down ? 0.015 : 0.035)

View File

@@ -4,14 +4,10 @@
Math.hash = s => { for (var i = 0, h = 9; i < s.length;) h = Math.imul(h ^ s.charCodeAt(i++), 9 ** 9); return h ^ h >>> 9 } Math.hash = s => { for (var i = 0, h = 9; i < s.length;) h = Math.imul(h ^ s.charCodeAt(i++), 9 ** 9); return h ^ h >>> 9 }
// const date1 = new Date() // const date1 = new Date()
// Math.seed = date1.getUTCDate() * date1.getUTCFullYear(); // daily seed, day + year // console.log(date1.getUTCHours())
// Math.seed = Date.now() //random every time: just the time in seconds UTC // document.getElementById("seed").placeholder = Math.initialSeed = String(date1.getUTCDate() * date1.getUTCFullYear()) // daily seed, day + year
// Math.seed = Math.abs(Math.hash(String(Date.now()))) //update randomizer seed in case the player changed it
// document.getElementById("seed").placeholder = Math.seed = Math.initialSeed = Math.floor(Date.now() % 100000) //random every time: just the time in milliseconds UTC document.getElementById("seed").placeholder = Math.initialSeed = Math.floor(Date.now() % 100000) //random every time: just the time in milliseconds UTC
document.getElementById("seed").placeholder = Math.initialSeed = String(Math.floor(Date.now() % 100000))
Math.seed = Math.abs(Math.hash(Math.initialSeed)) //update randomizer seed in case the player changed it Math.seed = Math.abs(Math.hash(Math.initialSeed)) //update randomizer seed in case the player changed it
Math.seededRandom = function(min = 0, max = 1) { // in order to work 'Math.seed' must NOT be undefined Math.seededRandom = function(min = 0, max = 1) { // in order to work 'Math.seed' must NOT be undefined
Math.seed = (Math.seed * 9301 + 49297) % 233280; Math.seed = (Math.seed * 9301 + 49297) % 233280;
@@ -400,15 +396,12 @@ ${simulation.isCheating ? "<br><br><em>lore disabled</em>": ""}
//update tech text //disable not allowed tech //update tech text //disable not allowed tech
for (let i = 0, len = tech.tech.length; i < len; i++) { for (let i = 0, len = tech.tech.length; i < len; i++) {
const techID = document.getElementById("tech-" + i) const techID = document.getElementById("tech-" + i)
if (!tech.tech[i].isExperimentHide && (!tech.tech[i].isNonRefundable || tech.tech[i].isExperimentalMode || (localSettings.isJunkExperiment && tech.tech[i].isJunk))) { if (!tech.tech[i].isExperimentHide && !tech.tech[i].isNonRefundable && (!tech.tech[i].isJunk || tech.tech[i].isExperimentalMode || localSettings.isJunkExperiment)) {
if (tech.tech[i].allowed() || isAllowed || tech.tech[i].count > 0) { if (tech.tech[i].allowed() || isAllowed || tech.tech[i].count > 0) {
// console.log(tech.tech[i].name, isAllowed, tech.tech[i].count, tech.haveGunCheck("nail gun"))
const techCountText = tech.tech[i].count > 1 ? `(${tech.tech[i].count}x)` : ""; const techCountText = tech.tech[i].count > 1 ? `(${tech.tech[i].count}x)` : "";
// <div class="circle-grid-small research" style="position:absolute; top:13px; left:30px;opacity:0.85;"></div> // <div class="circle-grid-small research" style="position:absolute; top:13px; left:30px;opacity:0.85;"></div>
if (tech.tech[i].isFieldTech) { if (tech.tech[i].isFieldTech) {
techID.classList.remove('experiment-grid-hide'); techID.classList.remove('experiment-grid-hide');
techID.innerHTML = ` techID.innerHTML = `
<div class="grid-title"> <div class="grid-title">
<span style="position:relative;"> <span style="position:relative;">
@@ -430,8 +423,7 @@ ${simulation.isCheating ? "<br><br><em>lore disabled</em>": ""}
</span> </span>
&nbsp; &nbsp; &nbsp; &nbsp; ${tech.tech[i].link} ${techCountText}</div>${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description} &nbsp; &nbsp; &nbsp; &nbsp; ${tech.tech[i].link} ${techCountText}</div>${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}
</div>` </div>`
} else } else if (tech.tech[i].isJunk) {
if (tech.tech[i].isJunk) {
techID.innerHTML = `<div class="grid-title"><div class="circle-grid junk"></div> &nbsp; ${tech.tech[i].link} ${techCountText}</div>${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() : tech.tech[i].description}</div>` techID.innerHTML = `<div class="grid-title"><div class="circle-grid junk"></div> &nbsp; ${tech.tech[i].link} ${techCountText}</div>${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() : tech.tech[i].description}</div>`
} else if (tech.tech[i].isExperimentalMode) { } else if (tech.tech[i].isExperimentalMode) {
techID.innerHTML = `<div class="grid-title">${tech.tech[i].name}</div>${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}</div>` techID.innerHTML = `<div class="grid-title">${tech.tech[i].name}</div>${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}</div>`
@@ -525,7 +517,7 @@ ${simulation.isCheating ? "<br><br><em>lore disabled</em>": ""}
lore.setTechGoal() lore.setTechGoal()
localSettings.difficultyMode = Number(document.getElementById("difficulty-select-experiment").value) localSettings.difficultyMode = Number(document.getElementById("difficulty-select-experiment").value)
document.getElementById("difficulty-select").value = document.getElementById("difficulty-select-experiment").value document.getElementById("difficulty-select").value = document.getElementById("difficulty-select-experiment").value
localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
}); });
//add tooltips //add tooltips
for (let i = 0, len = tech.tech.length; i < len; i++) { for (let i = 0, len = tech.tech.length; i < len; i++) {
@@ -756,7 +748,7 @@ const input = {
document.getElementById("splash-previous-gun").innerHTML = cleanText(input.key.previousGun)[0] document.getElementById("splash-previous-gun").innerHTML = cleanText(input.key.previousGun)[0]
localSettings.key = input.key localSettings.key = input.key
localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
}, },
focus: null, focus: null,
setTextFocus() { setTextFocus() {
@@ -1061,7 +1053,12 @@ window.addEventListener("keydown", function(event) {
break break
case "h": case "h":
// m.health = Infinity // m.health = Infinity
if (m.immuneCycle === Infinity) {
m.immuneCycle = 0 //you can't take damage
} else {
m.immuneCycle = Infinity //you can't take damage m.immuneCycle = Infinity //you can't take damage
}
// m.energy = Infinity // m.energy = Infinity
// document.getElementById("health").style.display = "none" // document.getElementById("health").style.display = "none"
// document.getElementById("health-bg").style.display = "none" // document.getElementById("health-bg").style.display = "none"
@@ -1175,8 +1172,38 @@ document.body.addEventListener("wheel", (e) => {
//********************************************************************** //**********************************************************************
// local storage // local storage
//********************************************************************** //**********************************************************************
let localSettings = JSON.parse(localStorage.getItem("localSettings")); let localSettings
function localstorageCheck() {
try {
return 'localStorage' in window && window['localStorage'] !== null;
} catch (e) {
return false;
}
}
if (localstorageCheck()) {
localSettings = JSON.parse(localStorage.getItem("localSettings"))
if (localSettings) { if (localSettings) {
localSettings.isAllowed = true
localSettings.isEmpty = false
console.log('localStorage is enabled')
} else {
console.log('localStorage is enabled, local settings empty')
localSettings = {
isAllowed: true,
isEmpty: true
}
}
} else {
localSettings = { isAllowed: false }
console.log("localStorage is disabled")
}
if (localSettings.isAllowed && !localSettings.isEmpty) {
console.log('restoring previous settings')
if (localSettings.key) { if (localSettings.key) {
input.key = localSettings.key input.key = localSettings.key
} else { } else {
@@ -1200,6 +1227,7 @@ if (localSettings) {
} }
document.getElementById("fps-select").value = localSettings.fpsCapDefault document.getElementById("fps-select").value = localSettings.fpsCapDefault
} else { } else {
console.log('setting default localSettings')
localSettings = { localSettings = {
isJunkExperiment: false, isJunkExperiment: false,
isCommunityMaps: false, isCommunityMaps: false,
@@ -1213,7 +1241,7 @@ if (localSettings) {
key: undefined key: undefined
}; };
input.setDefault() input.setDefault()
localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
document.getElementById("community-maps").checked = localSettings.isCommunityMaps document.getElementById("community-maps").checked = localSettings.isCommunityMaps
simulation.isCommunityMaps = localSettings.isCommunityMaps simulation.isCommunityMaps = localSettings.isCommunityMaps
document.getElementById("difficulty-select").value = localSettings.difficultyMode document.getElementById("difficulty-select").value = localSettings.difficultyMode
@@ -1235,13 +1263,13 @@ document.getElementById("fps-select").addEventListener("input", () => {
simulation.fpsCapDefault = Number(value) simulation.fpsCapDefault = Number(value)
} }
localSettings.fpsCapDefault = value localSettings.fpsCapDefault = value
localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
}); });
document.getElementById("community-maps").addEventListener("input", () => { document.getElementById("community-maps").addEventListener("input", () => {
simulation.isCommunityMaps = document.getElementById("community-maps").checked simulation.isCommunityMaps = document.getElementById("community-maps").checked
localSettings.isCommunityMaps = simulation.isCommunityMaps localSettings.isCommunityMaps = simulation.isCommunityMaps
localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
}); });
// difficulty-select-experiment event listener is set in build.makeGrid // difficulty-select-experiment event listener is set in build.makeGrid
@@ -1250,7 +1278,7 @@ document.getElementById("difficulty-select").addEventListener("input", () => {
lore.setTechGoal() lore.setTechGoal()
localSettings.difficultyMode = simulation.difficultyMode localSettings.difficultyMode = simulation.difficultyMode
localSettings.levelsClearedLastGame = 0 //after changing difficulty, reset run history localSettings.levelsClearedLastGame = 0 //after changing difficulty, reset run history
localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
}); });

View File

@@ -17,11 +17,9 @@ const level = {
// simulation.isHorizontalFlipped = true // simulation.isHorizontalFlipped = true
// m.setField("time dilation") // m.setField("time dilation")
// b.giveGuns("harpoon") // b.giveGuns("harpoon")
// tech.giveTech("unaaq") // for (let i = 0; i < 9; i++) tech.giveTech("smelting")
// tech.giveTech("railgun") // tech.giveTech("UHMWPE")
// tech.giveTech("capacitor bank") // tech.giveTech("grappling hook")
// tech.giveTech("half-wave rectifier")
// for (let i = 0; i < 3; i++) tech.giveTech("reticulum")
// for (let i = 0; i < 2; i++) powerUps.directSpawn(0, 0, "tech"); // for (let i = 0; i < 2; i++) powerUps.directSpawn(0, 0, "tech");
// for (let i = 0; i < 3; i++) tech.giveTech("undefined") // for (let i = 0; i < 3; i++) tech.giveTech("undefined")
// for (let i = 10; i < tech.tech.length; i++) { tech.tech[i].isBanished = true } // for (let i = 10; i < tech.tech.length; i++) { tech.tech[i].isBanished = true }
@@ -34,7 +32,7 @@ const level = {
// simulation.enableConstructMode() //used to build maps in testing mode // simulation.enableConstructMode() //used to build maps in testing mode
// level.reactor(); // level.reactor();
// level.testing(); //not in rotation, used for testing // level.testing(); //not in rotation, used for testing
// level.run()
if (simulation.isTraining) { level.walk(); } else { level.intro(); } if (simulation.isTraining) { level.walk(); } else { level.intro(); }
// powerUps.research.changeRerolls(3000) // powerUps.research.changeRerolls(3000)
@@ -43,9 +41,11 @@ const level = {
// lore.techCount = 3 // lore.techCount = 3
// simulation.isCheating = false //true; // simulation.isCheating = false //true;
// localSettings.loreCount = 2; //this sets what conversation is heard // localSettings.loreCount = 2; //this sets what conversation is heard
// localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage // if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
// level.onLevel = -1 //this sets level.levels[level.onLevel] = undefined which is required to run the conversation // level.onLevel = -1 //this sets level.levels[level.onLevel] = undefined which is required to run the conversation
// level.null() // level.null()
// lore.unlockTesting();
// tech.giveTech("tinker"); //show junk tech in experiment mode
} else { } else {
spawn.setSpawnList(); //picks a couple mobs types for a themed random mob spawns spawn.setSpawnList(); //picks a couple mobs types for a themed random mob spawns
// spawn.pickList = ["focuser", "focuser"] // spawn.pickList = ["focuser", "focuser"]
@@ -53,7 +53,7 @@ const level = {
if (!simulation.isCheating && !build.isExperimentRun && !simulation.isTraining) { if (!simulation.isCheating && !build.isExperimentRun && !simulation.isTraining) {
localSettings.runCount += level.levelsCleared //track the number of total runs locally localSettings.runCount += level.levelsCleared //track the number of total runs locally
localSettings.levelsClearedLastGame = level.levelsCleared localSettings.levelsClearedLastGame = level.levelsCleared
localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
} }
} }
if (!simulation.isTraining) level.levelAnnounce(); if (!simulation.isTraining) level.levelAnnounce();
@@ -128,7 +128,7 @@ const level = {
m.dmgScale = 1; //damage done by player decreases each level m.dmgScale = 1; //damage done by player decreases each level
simulation.accelScale = 1 //mob acceleration increases each level simulation.accelScale = 1 //mob acceleration increases each level
simulation.CDScale = 1 //mob CD time decreases each level simulation.CDScale = 1 //mob CD time decreases each level
simulation.dmgScale = Math.max(0.1, 0.35 * simulation.difficulty) //damage done by mobs scales with total levels simulation.dmgScale = Math.max(0.1, 0.34 * 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; simulation.healScale = 1 / (1 + simulation.difficulty * 0.055) //a higher denominator makes for lower heals // m.health += heal * simulation.healScale;
}, },
difficultyIncrease(num = 1) { difficultyIncrease(num = 1) {
@@ -138,7 +138,7 @@ const level = {
if (simulation.accelScale < 6) simulation.accelScale *= 1.025 //mob acceleration increases 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 if (simulation.CDScale > 0.15) simulation.CDScale *= 0.965 //mob CD time decreases each level
} }
simulation.dmgScale = Math.max(0.1, 0.35 * simulation.difficulty) //damage done by mobs scales with total levels simulation.dmgScale = Math.max(0.1, 0.34 * 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; 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}`) // console.log(`CD = ${simulation.CDScale}`)
}, },
@@ -2385,7 +2385,7 @@ const level = {
lore.sentence = 0 //what part of the conversation to start on lore.sentence = 0 //what part of the conversation to start on
lore.conversation[lore.chapter][lore.sentence]() lore.conversation[lore.chapter][lore.sentence]()
localSettings.loreCount++ //hear the next conversation next time you win localSettings.loreCount++ //hear the next conversation next time you win
localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
} }
// const hazardSlime = level.hazard(-1800, 150, 3600, 650, 0.004, "hsla(160, 100%, 35%,0.75)") // const hazardSlime = level.hazard(-1800, 150, 3600, 650, 0.004, "hsla(160, 100%, 35%,0.75)")
@@ -2488,63 +2488,39 @@ const level = {
testing() { testing() {
const button = level.button(1000, 0) const button = level.button(1000, 0)
spawn.bodyRect(1000, -50, 50, 50); spawn.bodyRect(1000, -50, 50, 50);
// const toggle = level.toggle(200, -700)
level.custom = () => { level.custom = () => {
// button.draw();
ctx.fillStyle = "rgba(0,255,255,0.1)"; ctx.fillStyle = "rgba(0,255,255,0.1)";
ctx.fillRect(6400, -550, 300, 350); ctx.fillRect(6400, -550, 300, 350);
level.exit.drawAndCheck(); level.exit.drawAndCheck();
level.enter.draw(); level.enter.draw();
}; };
level.customTopLayer = () => { level.customTopLayer = () => {
button.query(); button.query();
button.draw(); button.draw();
vanish1.query();
// vanish2.query();
// vanish3.query();
// vanish4.query();
// vanish5.query();
}; };
const vanish1 = level.vanish(1400, -200, 200, 50) //x, y, width, height, hide = { x: 0, y: 0 } //hide should just be somewhere behind the map so the player can't see it
// const vanish2 = level.vanish(1825, -150, 150, 150) //x, y, width, height, hide = { x: 0, y: 0 } //hide should just be somewhere behind the map so the player can't see it
// const vanish3 = level.vanish(1975, -150, 150, 150) //x, y, width, height, hide = { x: 0, y: 0 } //hide should just be somewhere behind the map so the player can't see it
// const vanish4 = level.vanish(1825, -300, 150, 150) //x, y, width, height, hide = { x: 0, y: 0 } //hide should just be somewhere behind the map so the player can't see it
// const vanish5 = level.vanish(1975, -300, 150, 150) //x, y, width, height, hide = { x: 0, y: 0 } //hide should just be somewhere behind the map so the player can't see it
level.setPosToSpawn(0, -450); //normal spawn level.setPosToSpawn(0, -450); //normal spawn
spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
level.exit.x = 200 //6500; level.exit.x = 6500;
level.exit.y = -430; level.exit.y = -230;
// level.difficultyIncrease(14); //hard mode level 7 // level.difficultyIncrease(14); //hard mode level 7
level.defaultZoom = 1500 level.defaultZoom = 1500
simulation.zoomTransition(level.defaultZoom) simulation.zoomTransition(level.defaultZoom)
document.body.style.backgroundColor = color.background //"#ddd"; document.body.style.backgroundColor = color.background //"#ddd";
// simulation.draw.mapFill = "#444"
// simulation.draw.bodyFill = "rgba(140,140,140,0.85)"
// simulation.draw.bodyStroke = "#222"
// level.addZone(level.exit.x, level.exit.y, 100, 30, "nextLevel");
spawn.mapRect(-950, 0, 8200, 800); //ground spawn.mapRect(-950, 0, 8200, 800); //ground
spawn.mapRect(-950, -1200, 800, 1400); //left wall spawn.mapRect(-950, -1200, 800, 1400); //left wall
spawn.mapRect(-950, -1800, 8200, 800); //roof spawn.mapRect(-950, -1800, 8200, 800); //roof
spawn.mapRect(-250, -400, 1000, 600); // shelf spawn.mapRect(-250, -400, 1000, 600); // shelf
spawn.mapRect(-250, -1200, 1000, 550); // shelf roof spawn.mapRect(-250, -1200, 1000, 550); // shelf roof
// powerUps.spawnStartingPowerUps(600, -800); // for (let i = 0; i < 10; ++i) powerUps.spawn(550, -800, "ammo", false);
// for (let i = 0; i < 50; ++i) powerUps.spawn(550, -800, "research", false);
// powerUps.spawn(350, -800, "gun", false);
function blockDoor(x, y, blockSize = 58) { function blockDoor(x, y, blockSize = 58) {
spawn.mapRect(x, y - 290, 40, 60); // door lip spawn.mapRect(x, y - 290, 40, 60); // door lip
spawn.mapRect(x, y, 40, 50); // 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);
// for (let i = 0; i < 200; i++) powerUps.directSpawn(710 + 1000 * Math.random(), -710 + 1000 * Math.random(), "tech");
spawn.mapRect(2500, -1200, 200, 750); //right wall spawn.mapRect(2500, -1200, 200, 750); //right wall
// blockDoor(2585, -210)
spawn.mapRect(2500, -200, 200, 300); //right wall spawn.mapRect(2500, -200, 200, 300); //right wall
spawn.mapRect(4500, -1200, 200, 650); //right wall spawn.mapRect(4500, -1200, 200, 650); //right wall
blockDoor(4585, -310) blockDoor(4585, -310)
@@ -2566,10 +2542,11 @@ const level = {
m.addHealth(Infinity) m.addHealth(Infinity)
// spawn.starter(1900, -500, 200) //big boy // spawn.starter(1900, -500, 200) //big boy
// for (let i = 0; i < 10; ++i) spawn.hopper(1900, -500)
// spawn.slashBoss(1900, -500) // spawn.slashBoss(1900, -500)
// spawn.launcherBoss(3200, -500) // spawn.launcherBoss(3200, -500)
// spawn.laserTargetingBoss(1700, -500) // spawn.laserTargetingBoss(1700, -500)
spawn.powerUpBoss(1900, -500) // spawn.powerUpBoss(1900, -500)
// spawn.powerUpBossBaby(3200, -500) // spawn.powerUpBossBaby(3200, -500)
// spawn.snakeBoss(1700, -500) // spawn.snakeBoss(1700, -500)
// spawn.streamBoss(3200, -500) // spawn.streamBoss(3200, -500)
@@ -2928,7 +2905,7 @@ const level = {
simulation.makeTextLog(`for (let i <span class='color-symbol'>=</span> 0; i <span class='color-symbol'><</span> localSettings.levelsClearedLastGame <span class='color-symbol'>/</span> 3; i<span class='color-symbol'>++</span>)`); simulation.makeTextLog(`for (let i <span class='color-symbol'>=</span> 0; i <span class='color-symbol'><</span> localSettings.levelsClearedLastGame <span class='color-symbol'>/</span> 3; i<span class='color-symbol'>++</span>)`);
simulation.makeTextLog(`{ powerUps.spawn(m.pos.x, m.pos.y, "tech") <em>//simulation superposition</em>}`); simulation.makeTextLog(`{ powerUps.spawn(m.pos.x, m.pos.y, "tech") <em>//simulation superposition</em>}`);
localSettings.levelsClearedLastGame = 0 //after getting bonus power ups reset run history localSettings.levelsClearedLastGame = 0 //after getting bonus power ups reset run history
localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
} }
} }
spawn.mapRect(2025, 0, 150, 50); //lid to floor hole spawn.mapRect(2025, 0, 150, 50); //lid to floor hole
@@ -7086,8 +7063,8 @@ const level = {
//Boss Spawning //Boss Spawning
if (simulation.difficulty > 3) { if (simulation.difficulty > 3) {
spawn.randomLevelBoss(6000, 700, ["pulsarBoss", "laserTargetingBoss", "powerUpBoss", "bomberBoss", "historyBoss", "orbitalBoss"]); spawn.randomLevelBoss(6000, 700, ["pulsarBoss", "laserTargetingBoss", "powerUpBoss", "bomberBoss", "historyBoss", "orbitalBoss"]);
if (simulation.difficulty > 10) spawn.shieldingBoss(7200, 500); // if (simulation.difficulty > 10) spawn.shieldingBoss(7200, 500);
if (simulation.difficulty > 20) spawn.randomLevelBoss(2000, 300, ["historyBoss", "shooterBoss"]); // if (simulation.difficulty > 20) spawn.randomLevelBoss(2000, 300, ["historyBoss", "shooterBoss"]);
} }
//Blocks //Blocks
@@ -7101,15 +7078,15 @@ const level = {
//Powerups //Powerups
powerUps.spawnStartingPowerUps(1250, 1500); powerUps.spawnStartingPowerUps(1250, 1500);
powerUps.spawnStartingPowerUps(1500, 1500); // powerUps.spawnStartingPowerUps(1500, 1500);
powerUps.spawn(8650, -200, "ammo");
powerUps.spawn(8650, -200, "ammo");
powerUps.spawn(8650, -200, "ammo");
powerUps.spawn(8650, -200, "ammo"); powerUps.spawn(8650, -200, "ammo");
// powerUps.spawn(8650, -200, "ammo");
// powerUps.spawn(8650, -200, "ammo");
// powerUps.spawn(8650, -200, "ammo");
powerUps.spawn(200, 50, "heal"); powerUps.spawn(200, 50, "heal");
powerUps.spawn(200, 50, "ammo"); // powerUps.spawn(200, 50, "ammo");
powerUps.spawn(200, 50, "ammo"); // powerUps.spawn(200, 50, "ammo");
powerUps.spawn(200, 50, "ammo"); // powerUps.spawn(200, 50, "ammo");
powerUps.addResearchToLevel() //needs to run after mobs are spawned powerUps.addResearchToLevel() //needs to run after mobs are spawned
spawn.secondaryBossChance(6600, 600) spawn.secondaryBossChance(6600, 600)
@@ -8431,7 +8408,7 @@ const level = {
const hazard = level.hazard(2300, -3090, 1700, 110, 0.005); const hazard = level.hazard(2300, -3090, 1700, 110, 0.005);
let isButtonTapped = false; let isButtonTapped = false;
if (b.inventory.length < 5) powerUps.spawn(3800, -3200, "gun"); // if (b.inventory.length < 5) powerUps.spawn(3800, -3200, "gun");
powerUps.spawn(3900, -3100, "heal", true, null, 30); powerUps.spawn(3900, -3100, "heal", true, null, 30);
powerUps.spawn(3900, -3100, "heal", true, null, 30); powerUps.spawn(3900, -3100, "heal", true, null, 30);
@@ -8519,7 +8496,7 @@ const level = {
spawn.shieldingBoss(3900, -3200, 70); spawn.shieldingBoss(3900, -3200, 70);
let randomBoss = Math.floor(Math.random() * 2); let randomBoss = Math.floor(Math.random() * 2);
if (simulation.difficulty > 5) spawn[["shooterBoss", "launcherBoss"][randomBoss]](7500, -150); if (simulation.difficulty > 5) spawn[["shooterBoss", "launcherBoss"][randomBoss]](7500, -150, 100, false);
else spawn[["shooter", "launcher"][randomBoss]](7500, -150, 150); else spawn[["shooter", "launcher"][randomBoss]](7500, -150, 150);
spawn[["shooter", "launcher"][randomBoss]](8500, -150, 150); spawn[["shooter", "launcher"][randomBoss]](8500, -150, 150);
@@ -8913,14 +8890,14 @@ const level = {
} }
powerUps.spawnRandomPowerUp(1700, -700); powerUps.spawnRandomPowerUp(1700, -700);
if (simulation.difficulty > 20) { // if (simulation.difficulty > 20) {
powerUps.spawn(4600, -700, "tech"); // powerUps.spawn(4600, -700, "tech");
} // }
powerUps.spawnRandomPowerUp(4700, -700); powerUps.spawnRandomPowerUp(4700, -700);
if (simulation.difficulty > 30) { // if (simulation.difficulty > 30) {
powerUps.spawn(6800, -1000, "tech"); // powerUps.spawn(6800, -1000, "tech");
} // }
powerUps.spawnRandomPowerUp(6900, -1000); powerUps.spawnRandomPowerUp(6900, -1000);
powerUps.spawn(9200, -5400, "tech"); powerUps.spawn(9200, -5400, "tech");
@@ -8928,12 +8905,12 @@ const level = {
if (simulation.difficulty > 10) { if (simulation.difficulty > 10) {
powerUps.spawn(9200, -5500, "tech"); powerUps.spawn(9200, -5500, "tech");
} }
if (simulation.difficulty > 20) { // if (simulation.difficulty > 20) {
powerUps.spawn(9200, -5600, "tech"); // powerUps.spawn(9200, -5600, "tech");
} // }
if (simulation.difficulty > 30) { // if (simulation.difficulty > 30) {
powerUps.spawn(9200, -5700, "tech"); // powerUps.spawn(9200, -5700, "tech");
} // }
powerUps.addResearchToLevel() //needs to run after mobs are spawned powerUps.addResearchToLevel() //needs to run after mobs are spawned
initialSpawn == true; initialSpawn == true;
} }
@@ -8996,7 +8973,7 @@ const level = {
crouch() { //learn to crouch crouch() { //learn to crouch
if (localSettings.isTrainingNotAttempted) { //after making it to the second training level if (localSettings.isTrainingNotAttempted) { //after making it to the second training level
localSettings.isTrainingNotAttempted = false // this makes the training button less obvious at the start screen localSettings.isTrainingNotAttempted = false // this makes the training button less obvious at the start screen
localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
} }
m.addHealth(Infinity) m.addHealth(Infinity)

View File

@@ -43,7 +43,7 @@ const lore = {
}, },
unlockTesting() { unlockTesting() {
if (localSettings.loreCount < 1) localSettings.loreCount = 1 if (localSettings.loreCount < 1) localSettings.loreCount = 1
localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
document.getElementById("control-testing").style.visibility = (localSettings.loreCount === 0) ? "hidden" : "visible" document.getElementById("control-testing").style.visibility = (localSettings.loreCount === 0) ? "hidden" : "visible"
// document.getElementById("experiment-button").style.visibility = (localSettings.loreCount === 0) ? "hidden" : "visible" // document.getElementById("experiment-button").style.visibility = (localSettings.loreCount === 0) ? "hidden" : "visible"
simulation.makeTextLog(`<span class='color-var'>lore</span>.unlockTesting()`, Infinity); simulation.makeTextLog(`<span class='color-var'>lore</span>.unlockTesting()`, Infinity);
@@ -406,13 +406,13 @@ const lore = {
lore.sentence-- lore.sentence--
lore.conversation[lore.chapter].splice(lore.sentence + 1, 1, () => { lore.anand.text("Not a human, maybe it's an artificial intelligence?") }) lore.conversation[lore.chapter].splice(lore.sentence + 1, 1, () => { lore.anand.text("Not a human, maybe it's an artificial intelligence?") })
localSettings.isHuman = false localSettings.isHuman = false
localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
} else if (input.up) { } else if (input.up) {
lore.anand.text("It jumped: so YES") lore.anand.text("It jumped: so YES")
lore.sentence-- lore.sentence--
lore.conversation[lore.chapter].splice(lore.sentence + 1, 1, () => { lore.anand.text("So you're just a regular human playing a video game!") }) lore.conversation[lore.chapter].splice(lore.sentence + 1, 1, () => { lore.anand.text("So you're just a regular human playing a video game!") })
localSettings.isHuman = true localSettings.isHuman = true
localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
} else if (m.alive) { } else if (m.alive) {
requestAnimationFrame(cycle); requestAnimationFrame(cycle);
} }

View File

@@ -872,7 +872,7 @@ const powerUps = {
powerUps.research.currentRerollCount = 0 powerUps.research.currentRerollCount = 0
if (tech.isTechDamage && who.name === "tech") m.damage(0.11) if (tech.isTechDamage && who.name === "tech") m.damage(0.11)
if (tech.isMassEnergy) m.energy += 2; if (tech.isMassEnergy) m.energy += 2;
if (tech.isMineDrop && bullet.length < 150) { if (tech.isMineDrop && bullet.length < 150 && Math.random() < 0.66) {
if (tech.isLaserMine && input.down) { if (tech.isLaserMine && input.down) {
b.laserMine(who.position) b.laserMine(who.position)
} else { } else {

View File

@@ -4399,7 +4399,7 @@ const spawn = {
this.fire(); this.fire();
}; };
}, },
shooterBoss(x, y, radius = 110) { shooterBoss(x, y, radius = 110, isSpawnBossPowerUp = true) {
mobs.spawn(x, y, 3, radius, "rgb(255,70,180)"); mobs.spawn(x, y, 3, radius, "rgb(255,70,180)");
let me = mob[mob.length - 1]; let me = mob[mob.length - 1];
setTimeout(() => { //fix mob in place, but allow rotation setTimeout(() => { //fix mob in place, but allow rotation
@@ -4440,7 +4440,7 @@ const spawn = {
}, 100); //have to wait a sec so the tether constraint doesn't attach to an orbital }, 100); //have to wait a sec so the tether constraint doesn't attach to an orbital
Matter.Body.setDensity(me, 0.008 + 0.0003 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger Matter.Body.setDensity(me, 0.008 + 0.0003 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
me.onDeath = function() { me.onDeath = function() {
powerUps.spawnBossPowerUp(this.position.x, this.position.y) if (isSpawnBossPowerUp) powerUps.spawnBossPowerUp(this.position.x, this.position.y)
// this.vertices = Matter.Vertices.hull(Matter.Vertices.clockwiseSort(this.vertices)) //helps collisions functions work better after vertex have been changed // this.vertices = Matter.Vertices.hull(Matter.Vertices.clockwiseSort(this.vertices)) //helps collisions functions work better after vertex have been changed
}; };
@@ -4746,7 +4746,7 @@ const spawn = {
} }
}; };
}, },
launcherBoss(x, y, radius = 90) { launcherBoss(x, y, radius = 90, isSpawnBossPowerUp = true) {
mobs.spawn(x, y, 6, radius, "rgb(150,150,255)"); mobs.spawn(x, y, 6, radius, "rgb(150,150,255)");
let me = mob[mob.length - 1]; let me = mob[mob.length - 1];
me.isBoss = true; me.isBoss = true;
@@ -4763,7 +4763,7 @@ const spawn = {
Matter.Body.setDensity(me, 0.0022 + 0.0002 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger Matter.Body.setDensity(me, 0.0022 + 0.0002 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
me.onDeath = function() { me.onDeath = function() {
powerUps.spawnBossPowerUp(this.position.x, this.position.y) if (isSpawnBossPowerUp) powerUps.spawnBossPowerUp(this.position.x, this.position.y)
// this.vertices = Matter.Vertices.hull(Matter.Vertices.clockwiseSort(this.vertices)) //helps collisions functions work better after vertex have been changed // this.vertices = Matter.Vertices.hull(Matter.Vertices.clockwiseSort(this.vertices)) //helps collisions functions work better after vertex have been changed
}; };
me.onDamage = function() {}; me.onDamage = function() {};

View File

@@ -657,9 +657,9 @@ const tech = {
frequency: 1, frequency: 1,
frequencyDefault: 1, frequencyDefault: 1,
allowed() { allowed() {
return !m.isShipMode && !tech.isAlwaysFire return !m.isShipMode && !tech.isAlwaysFire, !tech.isGrapple
}, },
requires: "not ship mode, not automatic", requires: "not ship mode, not automatic, grappling hook",
effect: () => { effect: () => {
tech.isFireMoveLock = true; tech.isFireMoveLock = true;
b.setFireCD(); b.setFireCD();
@@ -4831,7 +4831,7 @@ const tech = {
}, },
{ {
name: "booby trap", name: "booby trap",
description: "drop a <strong>mine</strong> after picking up a <strong>power up</strong><br><strong>+53%</strong> <strong class='color-j'>JUNK</strong> to the potential <strong class='color-m'>tech</strong> pool", description: "<strong>50%</strong> chance to drop a <strong>mine</strong> from <strong>power ups</strong><br><strong>+50%</strong> <strong class='color-j'>JUNK</strong> to the potential <strong class='color-m'>tech</strong> pool",
isGunTech: true, isGunTech: true,
maxCount: 1, maxCount: 1,
count: 0, count: 0,
@@ -4844,7 +4844,7 @@ const tech = {
effect() { effect() {
tech.isMineDrop = true; tech.isMineDrop = true;
if (tech.isMineDrop) b.mine(m.pos, { x: 0, y: 0 }, 0) if (tech.isMineDrop) b.mine(m.pos, { x: 0, y: 0 }, 0)
this.refundAmount += tech.addJunkTechToPool(0.53) this.refundAmount += tech.addJunkTechToPool(0.5)
}, },
refundAmount: 0, refundAmount: 0,
remove() { remove() {
@@ -5479,16 +5479,16 @@ const tech = {
}, },
{ {
name: "railgun", name: "railgun",
description: `harpoons are <strong>50% denser</strong>, but don't <strong>retract</strong><br>gain <strong>500%</strong> more harpoon <strong class='color-ammo'>ammo</strong> per ${powerUps.orb.ammo(1)}`, description: `<strong>harpoons</strong> are <strong>50% denser</strong>, but don't <strong>retract</strong><br>gain <strong>500%</strong> more harpoon <strong class='color-ammo'>ammo</strong> per ${powerUps.orb.ammo(1)}`,
isGunTech: true, isGunTech: true,
maxCount: 1, maxCount: 1,
count: 0, count: 0,
frequency: 2, frequency: 2,
frequencyDefault: 2, frequencyDefault: 2,
allowed() { allowed() {
return tech.haveGunCheck("harpoon") && !tech.isFilament && !tech.isHarpoonPowerUp return tech.haveGunCheck("harpoon") && !tech.isFilament && !tech.isHarpoonPowerUp && !tech.isGrapple
}, },
requires: "harpoon, not filament, toggling harpoon", requires: "harpoon, not filament, toggling harpoon, grappling hook",
ammoBonus: 5, ammoBonus: 5,
effect() { effect() {
tech.isRailGun = true; tech.isRailGun = true;
@@ -5555,9 +5555,36 @@ const tech = {
// tech.isRodAreaDamage = false; // tech.isRodAreaDamage = false;
// } // }
// }, // },
{
name: "grappling hook",
description: `<strong>harpoons</strong> attach to the <strong>map</strong> and pull you in<br><strong>rope</strong> extends much <strong>farther</strong> while you hold fire`,
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("harpoon") && !tech.isFilament && !tech.isHarpoonPowerUp && !tech.isRailGun && !tech.isFireMoveLock
},
requires: "harpoon, not railgun, filament, toggling harpoon, Higgs mechanism",
effect() {
tech.isGrapple = true;
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "harpoon") b.guns[i].chooseFireMethod()
}
},
remove() {
if (tech.isGrapple) {
tech.isGrapple = false;
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "harpoon") b.guns[i].chooseFireMethod()
}
}
}
},
{ {
name: "alternator", name: "alternator",
description: "<strong>harpoon</strong> drains no <strong class='color-f'>energy</strong><br><strong>railgun</strong> generates <strong class='color-f'>energy</strong>", //as they <strong>retract</strong><br><strong>crouch</strong> firing <strong>harpoon</strong> generates <strong class='color-f'>energy</strong>", description: "<strong>harpoon</strong> and <strong>grappling hook</strong> drain no <strong class='color-f'>energy</strong><br><strong>railgun</strong> generates <strong class='color-f'>energy</strong>", //as they <strong>retract</strong><br><strong>crouch</strong> firing <strong>harpoon</strong> generates <strong class='color-f'>energy</strong>",
isGunTech: true, isGunTech: true,
maxCount: 1, maxCount: 1,
count: 0, count: 0,
@@ -5615,8 +5642,8 @@ const tech = {
{ {
name: "smelting", name: "smelting",
// description: `spend ${powerUps.orb.ammo(2)}to upgrade the <strong>harpoon</strong><br>fire <strong>+1</strong> <strong>harpoon</strong> with each shot`, // description: `spend ${powerUps.orb.ammo(2)}to upgrade the <strong>harpoon</strong><br>fire <strong>+1</strong> <strong>harpoon</strong> with each shot`,
// description: `forge ${Math.ceil(0.6*(tech.isRailGun? 5: 1))} ammo into a new <strong>harpoon</strong><br>fire <strong>+1</strong> <strong>harpoon</strong> with each shot`, description: `forge <strong>2</strong> <strong class='color-ammo'>ammo</strong> into a new harpoon<br>fire <strong>+1</strong> <strong>harpoon</strong> with each shot`,
descriptionFunction() { return `forge <strong>${tech.isRailGun? 10: 2}</strong> <strong class='color-ammo'>ammo</strong> into a new harpoon<br>fire <strong>+1</strong> <strong>harpoon</strong> with each shot` }, // descriptionFunction() { return `forge <strong>${tech.isRailGun? 10: 2}</strong> <strong class='color-ammo'>ammo</strong> into a new harpoon<br>fire <strong>+1</strong> <strong>harpoon</strong> with each shot` },
isGunTech: true, isGunTech: true,
maxCount: 9, maxCount: 9,
count: 0, count: 0,
@@ -5629,7 +5656,7 @@ const tech = {
effect() { effect() {
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "harpoon") { if (b.guns[i].name === "harpoon") {
b.guns[i].ammo -= tech.isRailGun ? 10 : 2 b.guns[i].ammo -= 2
if (b.guns[i].ammo < 0) b.guns[i].ammo = 0 if (b.guns[i].ammo < 0) b.guns[i].ammo = 0
simulation.updateGunHUD(); simulation.updateGunHUD();
tech.extraHarpoons++; tech.extraHarpoons++;
@@ -5641,7 +5668,7 @@ const tech = {
if (tech.extraHarpoons) { if (tech.extraHarpoons) {
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "harpoon") { if (b.guns[i].name === "harpoon") {
b.guns[i].ammo += Math.ceil(b.guns[i].ammoPack) * 2 * tech.extraHarpoons b.guns[i].ammo += 2
simulation.updateGunHUD(); simulation.updateGunHUD();
break break
} }
@@ -5659,9 +5686,9 @@ const tech = {
frequency: 2, frequency: 2,
frequencyDefault: 2, frequencyDefault: 2,
allowed() { allowed() {
return tech.haveGunCheck("harpoon") && !tech.isRailGun return tech.haveGunCheck("harpoon") && !tech.isRailGun && !tech.isGrapple
}, },
requires: "harpoon", requires: "harpoon, not grappling hook, railgun",
effect() { effect() {
tech.isFilament = true; tech.isFilament = true;
}, },
@@ -5678,9 +5705,9 @@ const tech = {
frequency: 2, frequency: 2,
frequencyDefault: 2, frequencyDefault: 2,
allowed() { allowed() {
return tech.haveGunCheck("harpoon") && !tech.isRailGun return tech.haveGunCheck("harpoon") && !tech.isRailGun && !tech.isGrapple
}, },
requires: "harpoon", requires: "harpoon, not grappling hook, railgun",
effect() { effect() {
tech.isHarpoonPowerUp = true tech.isHarpoonPowerUp = true
}, },
@@ -7409,8 +7436,9 @@ const tech = {
}, },
requires: "", requires: "",
effect() { effect() {
console.log('hi')
localSettings.isJunkExperiment = true localSettings.isJunkExperiment = true
localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
}, },
remove() {} remove() {}
}, },
@@ -9382,5 +9410,6 @@ const tech = {
extraSuperBalls: null, extraSuperBalls: null,
isTimeCrystals: null, isTimeCrystals: null,
isGroundState: null, isGroundState: null,
isRailGun: null isRailGun: null,
isGrapple: null
} }

View File

@@ -1,19 +1,28 @@
******************************************************** NEXT PATCH ************************************************** ******************************************************** NEXT PATCH **************************************************
filament renamed UHMWPE tech grappling hook - can attack to walls and pull you towards the walls
unaaq renamed Bessemer process harpoon extends farther as you hold down fire, but no longer has auto-steering
toggling harpoon renamed induction furnace
half-wave rectifier renamed alternator
reticulum renamed smelting
smelting costs 2 ammo packs per upgrade
railgun works with smelting
JUNK tech: Higgs phase transition - spawn 3 tech, there is a chance to remove everything with a 5 minute halflife mobs do 4% less harm per difficulty level
railgun/harpoon auto-targeting is smarter at long distances with multiple small targets
but it still has trouble with moving targets
booby trap only has a 100 -> 50% chance to drop a mine when picking up power ups
added fallback for browsers that don't allow local storage
******************************************************** TODO ******************************************************** ******************************************************** TODO ********************************************************
make a variety of harpoon shapes? grappling hook
just a different railgun shape? new shape, different from harpoon
how to draw convex?
composite
draw the hook part directly
give player more control over motion while hanging and retracting
reduce friction effects so player swing around?
up down left right push player around?
lengthen and shrink the rope length?
scale velocity dampening with distance to grapple
get induction furnace working?
I'm not a fan of this tech, I'd be happy if it was basic harpoon only
tech - Plasma railgun tech - Plasma railgun
like foam, or phonon? like foam, or phonon?
@@ -23,11 +32,6 @@ pause time like invariant for other things...
charging railgun charging railgun
charging anything? charging anything?
tech: when this tech is ejected spawn one of every power up type
JUNK tech?
try to get grappling hook working again
bug - url sharing still broken sometimes bug - url sharing still broken sometimes
setting to remove UI, except health bar setting to remove UI, except health bar