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:
536
js/bullet.js
536
js/bullet.js
@@ -1348,6 +1348,285 @@ const b = {
|
||||
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) {
|
||||
const me = bullet.length;
|
||||
const returnRadius = 100 * Math.sqrt(harpoonSize)
|
||||
@@ -1505,42 +1784,77 @@ const b = {
|
||||
},
|
||||
do() {
|
||||
this.cycle++
|
||||
if (isReturn) {
|
||||
if (this.cycle > totalCycles) {
|
||||
if (m.energy < 0.05) { //snap rope if not enough energy
|
||||
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
|
||||
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 {
|
||||
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
|
||||
const face = {
|
||||
x: Math.cos(this.angle),
|
||||
y: Math.sin(this.angle)
|
||||
};
|
||||
const vectorGoal = Vector.normalise(Vector.sub(this.position, target.position));
|
||||
if (Vector.cross(vectorGoal, face) > 0) {
|
||||
Matter.Body.rotate(this, this.turnRate);
|
||||
} else {
|
||||
Matter.Body.rotate(this, -this.turnRate);
|
||||
}
|
||||
}
|
||||
if (isReturn || target) {
|
||||
if (isReturn) {
|
||||
if (this.cycle > totalCycles) {
|
||||
//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
|
||||
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 {
|
||||
this.grabPowerUp()
|
||||
}
|
||||
}
|
||||
|
||||
if (target) { //rotate towards the target
|
||||
const face = {
|
||||
x: Math.cos(this.angle),
|
||||
y: Math.sin(this.angle)
|
||||
};
|
||||
const vectorGoal = Vector.normalise(Vector.sub(this.position, target.position));
|
||||
if (Vector.cross(vectorGoal, face) > 0) {
|
||||
Matter.Body.rotate(this, this.turnRate);
|
||||
} else {
|
||||
Matter.Body.rotate(this, -this.turnRate);
|
||||
}
|
||||
}
|
||||
//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.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
|
||||
minDmgSpeed: 2,
|
||||
lookFrequency: 67 + Math.floor(7 * Math.random()),
|
||||
drain: 0.62 * tech.isLaserDiode * tech.laserFieldDrain,
|
||||
drain: 0.7 * tech.isLaserDiode * tech.laserFieldDrain,
|
||||
isDetonated: false,
|
||||
torqueMagnitude: 0.000003 * (Math.round(Math.random()) ? 1 : -1),
|
||||
range: 1500,
|
||||
@@ -5615,6 +5929,9 @@ const b = {
|
||||
if (tech.isRailGun) {
|
||||
this.do = this.railDo
|
||||
this.fire = this.railFire
|
||||
} else if (tech.isGrapple) {
|
||||
this.do = () => {}
|
||||
this.fire = this.grappleFire
|
||||
} else {
|
||||
this.do = () => {}
|
||||
this.fire = this.harpoonFire
|
||||
@@ -5643,57 +5960,6 @@ const b = {
|
||||
distance: 10000,
|
||||
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
|
||||
const range = 1200 * this.charge
|
||||
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.y -= recoil.y
|
||||
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;
|
||||
} else { //charging
|
||||
@@ -5784,6 +6101,31 @@ const b = {
|
||||
m.fireCDcycle = m.cycle + 10 //can't fire until mouse is released
|
||||
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() {
|
||||
const where = {
|
||||
x: m.pos.x + 30 * Math.cos(m.angle),
|
||||
@@ -5796,18 +6138,18 @@ const b = {
|
||||
//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 totalCycles = 7 * (tech.isFilament ? 1 + 0.01 * Math.min(110, this.ammo) : 1) * Math.sqrt(harpoonSize)
|
||||
const SPREAD = 0.1
|
||||
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
|
||||
|
||||
if (tech.extraHarpoons && !input.down) {
|
||||
if (tech.extraHarpoons && !input.down) { //multiple harpoons
|
||||
const SPREAD = 0.1
|
||||
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 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) {
|
||||
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))
|
||||
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) {
|
||||
this.ammo--
|
||||
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();
|
||||
m.fireCDcycle = m.cycle + 90 // cool down
|
||||
} 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) {
|
||||
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
|
||||
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, !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
|
||||
}
|
||||
const recoil = Vector.mult(Vector.normalise(Vector.sub(where, m.pos)), input.down ? 0.015 : 0.035)
|
||||
|
||||
72
js/index.js
72
js/index.js
@@ -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 }
|
||||
|
||||
// const date1 = new Date()
|
||||
// Math.seed = date1.getUTCDate() * date1.getUTCFullYear(); // daily seed, day + year
|
||||
// Math.seed = Date.now() //random every time: just the time in seconds UTC
|
||||
// Math.seed = Math.abs(Math.hash(String(Date.now()))) //update randomizer seed in case the player changed it
|
||||
// console.log(date1.getUTCHours())
|
||||
// document.getElementById("seed").placeholder = Math.initialSeed = String(date1.getUTCDate() * date1.getUTCFullYear()) // daily seed, day + year
|
||||
|
||||
// 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 = String(Math.floor(Date.now() % 100000))
|
||||
document.getElementById("seed").placeholder = Math.initialSeed = Math.floor(Date.now() % 100000) //random every time: just the time in milliseconds UTC
|
||||
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.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
|
||||
for (let i = 0, len = tech.tech.length; i < len; 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) {
|
||||
// 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)` : "";
|
||||
|
||||
// <div class="circle-grid-small research" style="position:absolute; top:13px; left:30px;opacity:0.85;"></div>
|
||||
if (tech.tech[i].isFieldTech) {
|
||||
techID.classList.remove('experiment-grid-hide');
|
||||
|
||||
techID.innerHTML = `
|
||||
<div class="grid-title">
|
||||
<span style="position:relative;">
|
||||
@@ -430,8 +423,7 @@ ${simulation.isCheating ? "<br><br><em>lore disabled</em>": ""}
|
||||
</span>
|
||||
${tech.tech[i].link} ${techCountText}</div>${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}
|
||||
</div>`
|
||||
} else
|
||||
if (tech.tech[i].isJunk) {
|
||||
} else if (tech.tech[i].isJunk) {
|
||||
techID.innerHTML = `<div class="grid-title"><div class="circle-grid junk"></div> ${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) {
|
||||
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()
|
||||
localSettings.difficultyMode = Number(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
|
||||
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]
|
||||
|
||||
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,
|
||||
setTextFocus() {
|
||||
@@ -1061,7 +1053,12 @@ window.addEventListener("keydown", function(event) {
|
||||
break
|
||||
case "h":
|
||||
// m.health = Infinity
|
||||
m.immuneCycle = Infinity //you can't take damage
|
||||
if (m.immuneCycle === Infinity) {
|
||||
m.immuneCycle = 0 //you can't take damage
|
||||
} else {
|
||||
m.immuneCycle = Infinity //you can't take damage
|
||||
}
|
||||
|
||||
// m.energy = Infinity
|
||||
// document.getElementById("health").style.display = "none"
|
||||
// document.getElementById("health-bg").style.display = "none"
|
||||
@@ -1175,8 +1172,38 @@ document.body.addEventListener("wheel", (e) => {
|
||||
//**********************************************************************
|
||||
// local storage
|
||||
//**********************************************************************
|
||||
let localSettings = JSON.parse(localStorage.getItem("localSettings"));
|
||||
if (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) {
|
||||
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) {
|
||||
input.key = localSettings.key
|
||||
} else {
|
||||
@@ -1200,6 +1227,7 @@ if (localSettings) {
|
||||
}
|
||||
document.getElementById("fps-select").value = localSettings.fpsCapDefault
|
||||
} else {
|
||||
console.log('setting default localSettings')
|
||||
localSettings = {
|
||||
isJunkExperiment: false,
|
||||
isCommunityMaps: false,
|
||||
@@ -1213,7 +1241,7 @@ if (localSettings) {
|
||||
key: undefined
|
||||
};
|
||||
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
|
||||
simulation.isCommunityMaps = localSettings.isCommunityMaps
|
||||
document.getElementById("difficulty-select").value = localSettings.difficultyMode
|
||||
@@ -1235,13 +1263,13 @@ document.getElementById("fps-select").addEventListener("input", () => {
|
||||
simulation.fpsCapDefault = Number(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", () => {
|
||||
simulation.isCommunityMaps = document.getElementById("community-maps").checked
|
||||
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
|
||||
@@ -1250,7 +1278,7 @@ document.getElementById("difficulty-select").addEventListener("input", () => {
|
||||
lore.setTechGoal()
|
||||
localSettings.difficultyMode = simulation.difficultyMode
|
||||
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
|
||||
});
|
||||
|
||||
|
||||
|
||||
105
js/level.js
105
js/level.js
@@ -17,11 +17,9 @@ const level = {
|
||||
// simulation.isHorizontalFlipped = true
|
||||
// m.setField("time dilation")
|
||||
// b.giveGuns("harpoon")
|
||||
// tech.giveTech("unaaq")
|
||||
// tech.giveTech("railgun")
|
||||
// tech.giveTech("capacitor bank")
|
||||
// tech.giveTech("half-wave rectifier")
|
||||
// for (let i = 0; i < 3; i++) tech.giveTech("reticulum")
|
||||
// for (let i = 0; i < 9; i++) tech.giveTech("smelting")
|
||||
// tech.giveTech("UHMWPE")
|
||||
// tech.giveTech("grappling hook")
|
||||
// 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 = 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
|
||||
// level.reactor();
|
||||
// level.testing(); //not in rotation, used for testing
|
||||
|
||||
// level.run()
|
||||
if (simulation.isTraining) { level.walk(); } else { level.intro(); }
|
||||
|
||||
// powerUps.research.changeRerolls(3000)
|
||||
@@ -43,9 +41,11 @@ const level = {
|
||||
// lore.techCount = 3
|
||||
// simulation.isCheating = false //true;
|
||||
// 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.null()
|
||||
// lore.unlockTesting();
|
||||
// tech.giveTech("tinker"); //show junk tech in experiment mode
|
||||
} else {
|
||||
spawn.setSpawnList(); //picks a couple mobs types for a themed random mob spawns
|
||||
// spawn.pickList = ["focuser", "focuser"]
|
||||
@@ -53,7 +53,7 @@ const level = {
|
||||
if (!simulation.isCheating && !build.isExperimentRun && !simulation.isTraining) {
|
||||
localSettings.runCount += level.levelsCleared //track the number of total runs locally
|
||||
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();
|
||||
@@ -128,7 +128,7 @@ 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 = 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;
|
||||
},
|
||||
difficultyIncrease(num = 1) {
|
||||
@@ -138,7 +138,7 @@ const 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 = 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;
|
||||
// console.log(`CD = ${simulation.CDScale}`)
|
||||
},
|
||||
@@ -2385,7 +2385,7 @@ const level = {
|
||||
lore.sentence = 0 //what part of the conversation to start on
|
||||
lore.conversation[lore.chapter][lore.sentence]()
|
||||
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)")
|
||||
@@ -2488,63 +2488,39 @@ const level = {
|
||||
testing() {
|
||||
const button = level.button(1000, 0)
|
||||
spawn.bodyRect(1000, -50, 50, 50);
|
||||
|
||||
// const toggle = level.toggle(200, -700)
|
||||
level.custom = () => {
|
||||
// button.draw();
|
||||
ctx.fillStyle = "rgba(0,255,255,0.1)";
|
||||
ctx.fillRect(6400, -550, 300, 350);
|
||||
level.exit.drawAndCheck();
|
||||
|
||||
level.enter.draw();
|
||||
};
|
||||
level.customTopLayer = () => {
|
||||
button.query();
|
||||
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
|
||||
spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
|
||||
level.exit.x = 200 //6500;
|
||||
level.exit.y = -430;
|
||||
level.exit.x = 6500;
|
||||
level.exit.y = -230;
|
||||
|
||||
// level.difficultyIncrease(14); //hard mode level 7
|
||||
level.defaultZoom = 1500
|
||||
simulation.zoomTransition(level.defaultZoom)
|
||||
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, -1200, 800, 1400); //left wall
|
||||
spawn.mapRect(-950, -1800, 8200, 800); //roof
|
||||
spawn.mapRect(-250, -400, 1000, 600); // shelf
|
||||
spawn.mapRect(-250, -1200, 1000, 550); // shelf roof
|
||||
// powerUps.spawnStartingPowerUps(600, -800);
|
||||
// for (let i = 0; i < 50; ++i) powerUps.spawn(550, -800, "research", false);
|
||||
// powerUps.spawn(350, -800, "gun", false);
|
||||
// for (let i = 0; i < 10; ++i) powerUps.spawn(550, -800, "ammo", false);
|
||||
|
||||
function blockDoor(x, y, blockSize = 58) {
|
||||
spawn.mapRect(x, y - 290, 40, 60); // door lip
|
||||
spawn.mapRect(x, y, 40, 50); // door lip
|
||||
for (let i = 0; i < 4; ++i) spawn.bodyRect(x + 5, y - 260 + i * blockSize, 30, blockSize);
|
||||
}
|
||||
// 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
|
||||
// blockDoor(2585, -210)
|
||||
spawn.mapRect(2500, -200, 200, 300); //right wall
|
||||
spawn.mapRect(4500, -1200, 200, 650); //right wall
|
||||
blockDoor(4585, -310)
|
||||
@@ -2566,10 +2542,11 @@ const level = {
|
||||
m.addHealth(Infinity)
|
||||
|
||||
// spawn.starter(1900, -500, 200) //big boy
|
||||
// for (let i = 0; i < 10; ++i) spawn.hopper(1900, -500)
|
||||
// spawn.slashBoss(1900, -500)
|
||||
// spawn.launcherBoss(3200, -500)
|
||||
// spawn.laserTargetingBoss(1700, -500)
|
||||
spawn.powerUpBoss(1900, -500)
|
||||
// spawn.powerUpBoss(1900, -500)
|
||||
// spawn.powerUpBossBaby(3200, -500)
|
||||
// spawn.snakeBoss(1700, -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(`{ powerUps.spawn(m.pos.x, m.pos.y, "tech") <em>//simulation superposition</em>}`);
|
||||
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
|
||||
@@ -7086,8 +7063,8 @@ const level = {
|
||||
//Boss Spawning
|
||||
if (simulation.difficulty > 3) {
|
||||
spawn.randomLevelBoss(6000, 700, ["pulsarBoss", "laserTargetingBoss", "powerUpBoss", "bomberBoss", "historyBoss", "orbitalBoss"]);
|
||||
if (simulation.difficulty > 10) spawn.shieldingBoss(7200, 500);
|
||||
if (simulation.difficulty > 20) spawn.randomLevelBoss(2000, 300, ["historyBoss", "shooterBoss"]);
|
||||
// if (simulation.difficulty > 10) spawn.shieldingBoss(7200, 500);
|
||||
// if (simulation.difficulty > 20) spawn.randomLevelBoss(2000, 300, ["historyBoss", "shooterBoss"]);
|
||||
}
|
||||
|
||||
//Blocks
|
||||
@@ -7101,15 +7078,15 @@ const level = {
|
||||
|
||||
//Powerups
|
||||
powerUps.spawnStartingPowerUps(1250, 1500);
|
||||
powerUps.spawnStartingPowerUps(1500, 1500);
|
||||
powerUps.spawn(8650, -200, "ammo");
|
||||
powerUps.spawn(8650, -200, "ammo");
|
||||
powerUps.spawn(8650, -200, "ammo");
|
||||
// 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(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
|
||||
spawn.secondaryBossChance(6600, 600)
|
||||
@@ -8431,7 +8408,7 @@ const level = {
|
||||
const hazard = level.hazard(2300, -3090, 1700, 110, 0.005);
|
||||
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);
|
||||
|
||||
@@ -8519,7 +8496,7 @@ const level = {
|
||||
spawn.shieldingBoss(3900, -3200, 70);
|
||||
|
||||
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);
|
||||
spawn[["shooter", "launcher"][randomBoss]](8500, -150, 150);
|
||||
|
||||
@@ -8913,14 +8890,14 @@ const level = {
|
||||
}
|
||||
powerUps.spawnRandomPowerUp(1700, -700);
|
||||
|
||||
if (simulation.difficulty > 20) {
|
||||
powerUps.spawn(4600, -700, "tech");
|
||||
}
|
||||
// if (simulation.difficulty > 20) {
|
||||
// powerUps.spawn(4600, -700, "tech");
|
||||
// }
|
||||
powerUps.spawnRandomPowerUp(4700, -700);
|
||||
|
||||
if (simulation.difficulty > 30) {
|
||||
powerUps.spawn(6800, -1000, "tech");
|
||||
}
|
||||
// if (simulation.difficulty > 30) {
|
||||
// powerUps.spawn(6800, -1000, "tech");
|
||||
// }
|
||||
powerUps.spawnRandomPowerUp(6900, -1000);
|
||||
|
||||
powerUps.spawn(9200, -5400, "tech");
|
||||
@@ -8928,12 +8905,12 @@ const level = {
|
||||
if (simulation.difficulty > 10) {
|
||||
powerUps.spawn(9200, -5500, "tech");
|
||||
}
|
||||
if (simulation.difficulty > 20) {
|
||||
powerUps.spawn(9200, -5600, "tech");
|
||||
}
|
||||
if (simulation.difficulty > 30) {
|
||||
powerUps.spawn(9200, -5700, "tech");
|
||||
}
|
||||
// if (simulation.difficulty > 20) {
|
||||
// powerUps.spawn(9200, -5600, "tech");
|
||||
// }
|
||||
// if (simulation.difficulty > 30) {
|
||||
// powerUps.spawn(9200, -5700, "tech");
|
||||
// }
|
||||
powerUps.addResearchToLevel() //needs to run after mobs are spawned
|
||||
initialSpawn == true;
|
||||
}
|
||||
@@ -8996,7 +8973,7 @@ const level = {
|
||||
crouch() { //learn to crouch
|
||||
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
|
||||
localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
|
||||
if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
|
||||
}
|
||||
|
||||
m.addHealth(Infinity)
|
||||
|
||||
@@ -43,7 +43,7 @@ const lore = {
|
||||
},
|
||||
unlockTesting() {
|
||||
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("experiment-button").style.visibility = (localSettings.loreCount === 0) ? "hidden" : "visible"
|
||||
simulation.makeTextLog(`<span class='color-var'>lore</span>.unlockTesting()`, Infinity);
|
||||
@@ -406,13 +406,13 @@ const lore = {
|
||||
lore.sentence--
|
||||
lore.conversation[lore.chapter].splice(lore.sentence + 1, 1, () => { lore.anand.text("Not a human, maybe it's an artificial intelligence?") })
|
||||
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) {
|
||||
lore.anand.text("It jumped: so YES")
|
||||
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!") })
|
||||
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) {
|
||||
requestAnimationFrame(cycle);
|
||||
}
|
||||
|
||||
@@ -872,7 +872,7 @@ const powerUps = {
|
||||
powerUps.research.currentRerollCount = 0
|
||||
if (tech.isTechDamage && who.name === "tech") m.damage(0.11)
|
||||
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) {
|
||||
b.laserMine(who.position)
|
||||
} else {
|
||||
|
||||
@@ -4399,7 +4399,7 @@ const spawn = {
|
||||
this.fire();
|
||||
};
|
||||
},
|
||||
shooterBoss(x, y, radius = 110) {
|
||||
shooterBoss(x, y, radius = 110, isSpawnBossPowerUp = true) {
|
||||
mobs.spawn(x, y, 3, radius, "rgb(255,70,180)");
|
||||
let me = mob[mob.length - 1];
|
||||
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
|
||||
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() {
|
||||
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
|
||||
};
|
||||
|
||||
@@ -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)");
|
||||
let me = mob[mob.length - 1];
|
||||
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
|
||||
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
|
||||
};
|
||||
me.onDamage = function() {};
|
||||
|
||||
65
js/tech.js
65
js/tech.js
@@ -657,9 +657,9 @@ const tech = {
|
||||
frequency: 1,
|
||||
frequencyDefault: 1,
|
||||
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: () => {
|
||||
tech.isFireMoveLock = true;
|
||||
b.setFireCD();
|
||||
@@ -4831,7 +4831,7 @@ const tech = {
|
||||
},
|
||||
{
|
||||
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,
|
||||
maxCount: 1,
|
||||
count: 0,
|
||||
@@ -4844,7 +4844,7 @@ const tech = {
|
||||
effect() {
|
||||
tech.isMineDrop = true;
|
||||
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,
|
||||
remove() {
|
||||
@@ -5479,16 +5479,16 @@ const tech = {
|
||||
},
|
||||
{
|
||||
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,
|
||||
maxCount: 1,
|
||||
count: 0,
|
||||
frequency: 2,
|
||||
frequencyDefault: 2,
|
||||
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,
|
||||
effect() {
|
||||
tech.isRailGun = true;
|
||||
@@ -5555,9 +5555,36 @@ const tech = {
|
||||
// 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",
|
||||
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,
|
||||
maxCount: 1,
|
||||
count: 0,
|
||||
@@ -5615,8 +5642,8 @@ const tech = {
|
||||
{
|
||||
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: `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`,
|
||||
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` },
|
||||
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` },
|
||||
isGunTech: true,
|
||||
maxCount: 9,
|
||||
count: 0,
|
||||
@@ -5629,7 +5656,7 @@ const tech = {
|
||||
effect() {
|
||||
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
|
||||
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
|
||||
simulation.updateGunHUD();
|
||||
tech.extraHarpoons++;
|
||||
@@ -5641,7 +5668,7 @@ const tech = {
|
||||
if (tech.extraHarpoons) {
|
||||
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
|
||||
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();
|
||||
break
|
||||
}
|
||||
@@ -5659,9 +5686,9 @@ const tech = {
|
||||
frequency: 2,
|
||||
frequencyDefault: 2,
|
||||
allowed() {
|
||||
return tech.haveGunCheck("harpoon") && !tech.isRailGun
|
||||
return tech.haveGunCheck("harpoon") && !tech.isRailGun && !tech.isGrapple
|
||||
},
|
||||
requires: "harpoon",
|
||||
requires: "harpoon, not grappling hook, railgun",
|
||||
effect() {
|
||||
tech.isFilament = true;
|
||||
},
|
||||
@@ -5678,9 +5705,9 @@ const tech = {
|
||||
frequency: 2,
|
||||
frequencyDefault: 2,
|
||||
allowed() {
|
||||
return tech.haveGunCheck("harpoon") && !tech.isRailGun
|
||||
return tech.haveGunCheck("harpoon") && !tech.isRailGun && !tech.isGrapple
|
||||
},
|
||||
requires: "harpoon",
|
||||
requires: "harpoon, not grappling hook, railgun",
|
||||
effect() {
|
||||
tech.isHarpoonPowerUp = true
|
||||
},
|
||||
@@ -7409,8 +7436,9 @@ const tech = {
|
||||
},
|
||||
requires: "",
|
||||
effect() {
|
||||
console.log('hi')
|
||||
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() {}
|
||||
},
|
||||
@@ -9382,5 +9410,6 @@ const tech = {
|
||||
extraSuperBalls: null,
|
||||
isTimeCrystals: null,
|
||||
isGroundState: null,
|
||||
isRailGun: null
|
||||
isRailGun: null,
|
||||
isGrapple: null
|
||||
}
|
||||
36
todo.txt
36
todo.txt
@@ -1,19 +1,28 @@
|
||||
******************************************************** NEXT PATCH **************************************************
|
||||
|
||||
filament renamed UHMWPE
|
||||
unaaq renamed Bessemer process
|
||||
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
|
||||
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
|
||||
|
||||
******************************************************** TODO ********************************************************
|
||||
|
||||
make a variety of harpoon shapes?
|
||||
just a different railgun shape?
|
||||
grappling hook
|
||||
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
|
||||
like foam, or phonon?
|
||||
@@ -23,11 +32,6 @@ pause time like invariant for other things...
|
||||
charging railgun
|
||||
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
|
||||
|
||||
setting to remove UI, except health bar
|
||||
|
||||
Reference in New Issue
Block a user