harpoon tech

harpoon gun
  shaped more like a harpoon
  grabs power ups slower, and from the tip of the harpoon
  only uses energy on returning
  doesn't have thrust if there is no mob target

  tech: reticulum - make one more harpoon if there are mobs nearby that you are facing
    I'm letting this stack to 9 even though it's silly cause that is n-gon's style
  tech: ceramics now lets both harpoons and needles ignore shields
    this was coded poorly so if shield bugs show up it might be from this
  tech: fragmentation makes ~15% fewer nails for everything it affects
  tech: filament gives 3% length per ammo (was 1%)
    also length is capped at 75 ammo because after that it's just annoying
  tech: unaaq is longer at low ammo but scales slower at high ammo

bugs
  fixed laser collisions on player head when crouching
  returned experiment gun and field circles
This commit is contained in:
landgreen
2021-09-12 15:34:29 -07:00
parent f7cd48c3ff
commit f719c8edb9
9 changed files with 174 additions and 103 deletions

View File

@@ -726,7 +726,7 @@ const b = {
bullet[me].explodeRad = 300 * size;
bullet[me].onEnd = function() {
b.explosion(this.position, this.explodeRad); //makes bullet do explosive damage at end
if (tech.fragments) b.targetedNail(this.position, tech.fragments * 4)
if (tech.fragments) b.targetedNail(this.position, tech.fragments * Math.floor(2 + 2 * Math.random()))
}
bullet[me].minDmgSpeed = 1;
bullet[me].beforeDmg = function() {
@@ -751,7 +751,7 @@ const b = {
bullet[me].explodeRad = 305 * size;
bullet[me].onEnd = function() {
b.explosion(this.position, this.explodeRad); //makes bullet do explosive damage at end
if (tech.fragments) b.targetedNail(this.position, tech.fragments * 4)
if (tech.fragments) b.targetedNail(this.position, tech.fragments * Math.floor(2 + 2 * Math.random()))
}
bullet[me].minDmgSpeed = 1;
bullet[me].beforeDmg = function() {
@@ -786,7 +786,7 @@ const b = {
bullet[me].explodeRad = 350 * size + Math.floor(Math.random() * 50) + tech.isBlockExplode * 110
bullet[me].onEnd = function() {
b.explosion(this.position, this.explodeRad); //makes bullet do explosive damage at end
if (tech.fragments) b.targetedNail(this.position, tech.fragments * 4)
if (tech.fragments) b.targetedNail(this.position, tech.fragments * Math.floor(2 + 2 * Math.random()))
}
bullet[me].minDmgSpeed = 1;
bullet[me].beforeDmg = function() {
@@ -862,7 +862,7 @@ const b = {
bullet[me].explodeRad = 350 * size + Math.floor(Math.random() * 50) + tech.isBlockExplode * 100
bullet[me].onEnd = function() {
b.explosion(this.position, this.explodeRad); //makes bullet do explosive damage at end
if (tech.fragments) b.targetedNail(this.position, tech.fragments * 6)
if (tech.fragments) b.targetedNail(this.position, tech.fragments * 5)
}
bullet[me].beforeDmg = function() {
this.endCycle = 0; //bullet ends cycle after doing damage //this also triggers explosion
@@ -1108,14 +1108,13 @@ const b = {
b.grenade = grenadeDefault
}
},
harpoon(where, target, scale = 1, isReturn = false, ropeLength = 15, speed = 0) {
harpoon(where, target, angle = m.angle, scale = 1, isReturn = false, ropeLength = 15) {
const me = bullet.length;
let vector = "-40 2 -40 -2 30 -2 50 0 30 2"
if (scale !== 1) vector = `${-40*scale} 2 ${-40*scale} -2 ${30*scale} -2 ${50*scale} 0 ${30*scale} 2`
bullet[me] = Bodies.fromVertices(where.x, where.y, Vertices.fromPath(vector), {
// bullet[me] = Bodies.rectangle(where.x, where.y, 70 * size, 4.5 * size, {
// let vector = "-40 2 -40 -2 50 -3 30 2" //"-40 2 -40 -2 30 -2 50 0 30 2"
// if (scale !== 1) vector = `${-40*scale} 2 ${-40*scale} -2 ${50*scale} -3 ${30*scale} 2` //`${-40*scale} 2 ${-40*scale} -2 ${30*scale} -2 ${50*scale} 0 ${30*scale} 2`
bullet[me] = Bodies.fromVertices(where.x, where.y, [{ x: -40 * scale, y: 2, index: 0, isInternal: false }, { x: -40 * scale, y: -2, index: 1, isInternal: false }, { x: 50 * scale, y: -3, index: 3, isInternal: false }, { x: 30 * scale, y: 2, index: 4, isInternal: false }], {
cycle: 0,
angle: m.angle,
angle: angle,
friction: 1,
frictionAir: 0.4,
thrustMag: 0.1,
@@ -1124,18 +1123,23 @@ const b = {
drawStringFlip: (Math.round(Math.random()) ? 1 : -1),
dmg: 0, //damage done in addition to the damage from momentum
classType: "bullet",
endCycle: simulation.cycle + 50,
endCycle: simulation.cycle + ropeLength * 2.5,
collisionFilter: {
category: cat.bullet,
mask: cat.map | cat.body | cat.mob | cat.mobBullet | cat.mobShield
mask: tech.isNeedleShieldPierce ? cat.map | cat.body | cat.mob | cat.mobBullet : cat.map | cat.body | cat.mob | cat.mobBullet | cat.mobShield,
},
minDmgSpeed: 0,
lookFrequency: Math.floor(7 + Math.random() * 3),
density: 0.005, //0.001 is normal
beforeDmg(who) {
// console.log(Vector.magnitude(Vector.sub(this.position, m.pos)))
if (tech.isNeedleShieldPierce && who.isShielded) { //disable shields
who.isShielded = false
requestAnimationFrame(() => { who.isShielded = true });
}
if (!who.isBadTarget) {
if (tech.fragments) {
b.targetedNail(this.position, tech.fragments * 5)
b.targetedNail(this.vertices[2], tech.fragments * 4)
} else if (isReturn) {
this.do = this.returnToPlayer
} else {
@@ -1164,8 +1168,6 @@ const b = {
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();
if (m.energy > 0.003) m.energy -= 0.003
}
},
returnToPlayer() {
@@ -1187,20 +1189,24 @@ const b = {
// if you grabbed a power up, stop it near the player
for (let i = 0, len = powerUp.length; i < len; ++i) { //near power up
if (Vector.magnitudeSquared(Vector.sub(this.position, powerUp[i].position)) < 6000) {
Matter.Body.setVelocity(powerUp[i], { x: 0, y: 0 })
Matter.Body.setVelocity(powerUp[i], { x: 0, y: -2 })
// Matter.Body.setPosition(powerUp[i], this.position)
break
}
}
} else {
let isPulling = false
for (let i = 0, len = powerUp.length; i < len; ++i) { //near power up
if (Vector.magnitudeSquared(Vector.sub(this.position, powerUp[i].position)) < 3000) {
if (Vector.magnitudeSquared(Vector.sub(this.vertices[2], powerUp[i].position)) < 3000) {
Matter.Body.setVelocity(powerUp[i], this.velocity)
Matter.Body.setPosition(powerUp[i], this.position)
Matter.Body.setPosition(powerUp[i], this.vertices[2])
isPulling = true
this.endCycle += 0.5 //it pulls back slower, so this prevents it from ending early
break
}
}
const returnForce = Vector.mult(Vector.normalise(Vector.sub(this.position, m.pos)), this.thrustMag * this.mass)
if (m.energy > 0.005) m.energy -= 0.005
const returnForce = Vector.mult(Vector.normalise(Vector.sub(this.position, m.pos)), this.thrustMag * this.mass * (isPulling ? 0.5 : 1))
this.force.x -= returnForce.x
this.force.y -= returnForce.y
this.drawString()
@@ -1209,29 +1215,26 @@ const b = {
do() {
if (!m.isBodiesAsleep) {
this.cycle++
if (isReturn && this.cycle > ropeLength) {
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.003
this.do = () => {
this.force.y += this.mass * 0.003; //gravity
if (isReturn) {
if (this.cycle > ropeLength) {
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 = () => { this.force.y += this.mass * 0.001; }
} else { //return to player
this.do = this.returnToPlayer
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 { //return to player
this.do = this.returnToPlayer
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
}
}
if (this.cycle > 30) {
} else if (this.cycle > 30) {
this.frictionAir = 0.003
this.do = () => {
this.force.y += this.mass * 0.003; //gravity
}
this.do = () => { this.force.y += this.mass * 0.003; }
}
if (target) { //rotate missile towards the target
if (target) { //rotate towards the target
const face = {
x: Math.cos(this.angle),
y: Math.sin(this.angle)
@@ -1243,6 +1246,10 @@ const b = {
Matter.Body.rotate(this, -this.turnRate);
}
}
if (isReturn || target) {
this.force.x += this.thrustMag * this.mass * Math.cos(this.angle);
this.force.y += this.thrustMag * this.mass * Math.sin(this.angle);
}
// else if (!(this.cycle % 2)) { //look for a target if you don't have one
// simulation.drawList.push({ //add dmg to draw queue
// x: this.position.x,
@@ -1275,16 +1282,20 @@ const b = {
// this.frictionAir = 0.8
// }
// }
this.force.x += this.thrustMag * this.mass * Math.cos(this.angle);
this.force.y += this.thrustMag * this.mass * Math.sin(this.angle);
}
this.drawString()
},
});
Matter.Body.setVelocity(bullet[me], {
x: m.Vx / 2 + speed * Math.cos(bullet[me].angle),
y: m.Vy / 2 + speed * Math.sin(bullet[me].angle)
});
if (!isReturn && !target) {
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() {
this.force.y += this.mass * 0.001; //gravity
}
}
Composite.add(engine.world, bullet[me]); //add bullet to world
},
missile(where, angle, speed, size = 1) {
@@ -1312,7 +1323,7 @@ const b = {
},
onEnd() {
b.explosion(this.position, this.explodeRad * size); //makes bullet do explosive damage at end
if (tech.fragments) b.targetedNail(this.position, tech.fragments * 4)
if (tech.fragments) b.targetedNail(this.position, tech.fragments * Math.floor(2 + 2 * Math.random()))
},
lockedOn: null,
tryToLockOn() {
@@ -4057,7 +4068,7 @@ const b = {
if (tech.fragments) {
bullet[me].beforeDmg = function() {
if (this.speed > 4) {
b.targetedNail(this.position, tech.fragments * 8)
b.targetedNail(this.position, tech.fragments * 7)
this.endCycle = 0 //triggers despawn
}
}
@@ -5007,7 +5018,6 @@ const b = {
ammo: 0,
ammoPack: 1,
have: false,
fireCycle: 0,
do() {},
fire() {
const where = {
@@ -5019,7 +5029,9 @@ const b = {
target: null
}
//look for closest mob in player's LoS
const dir = { x: Math.cos(m.angle), y: Math.sin(m.angle) }; //make a vector for the player's direction of length 1
const dir = { x: Math.cos(m.angle), y: Math.sin(m.angle) }; //make a vector for the player's direction of length 1; used in dot product
const length = tech.isLargeHarpoon ? 1 + 0.15 * Math.sqrt(this.ammo) : 1
const totalCycles = 8 * (tech.isFilament ? 1 + Math.min(75, this.ammo) / 33 : 1)
if (m.crouch) {
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) {
@@ -5031,8 +5043,32 @@ const b = {
}
}
}
b.harpoon(where, closest.target, 1 + tech.isLargeHarpoon * this.ammo / 100, false)
b.harpoon(where, closest.target, m.angle, length, false)
m.fireCDcycle = m.cycle + 50 * b.fireCDscale; // cool down
} else if (tech.extraHarpoons) {
const range = 560 * (tech.isFilament ? 1 + this.ammo / 33 : 1)
let targetCount = 0
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 < range && dot > 0.9) { //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], Vector.angle(Vector.sub(where, mob[i].position), { x: 0, y: 0 }), length, true, totalCycles)
targetCount++
if (targetCount > tech.extraHarpoons) break
}
}
}
}
if (!targetCount) {
b.harpoon(where, null, m.angle, length, true, totalCycles) //if no target
} else if (targetCount > 0) {
this.ammo++ //make up for the ammo used up in fire()
simulation.updateGunHUD();
}
m.fireCDcycle = m.cycle + 180 //Infinity; // cool down
} else {
for (let i = 0, len = mob.length; i < len; ++i) {
if (mob[i].alive && !mob[i].isBadTarget && Matter.Query.ray(map, m.pos, mob[i].position).length === 0) {
@@ -5044,7 +5080,7 @@ const b = {
}
}
}
b.harpoon(where, closest.target, 1 + tech.isLargeHarpoon * this.ammo / 100, true, (m.crouch ? 10 : 8) * (tech.isFilament ? 1 + this.ammo / 100 : 1))
b.harpoon(where, closest.target, m.angle, length, true, totalCycles)
m.fireCDcycle = m.cycle + 180 //Infinity; // cool down
}
const recoil = Vector.mult(Vector.normalise(Vector.sub(where, m.pos)), m.crouch ? 0.015 : 0.035)
@@ -5139,7 +5175,7 @@ const b = {
// Matter.Body.setDensity(this, 0.001);
}
if (tech.fragments && this.speed > 10) {
b.targetedNail(this.position, tech.fragments * 15)
b.targetedNail(this.position, tech.fragments * 13)
this.endCycle = 0 //triggers despawn
}
},
@@ -5223,7 +5259,7 @@ const b = {
});
}
if (tech.fragments && this.speed > 10) {
b.targetedNail(this.position, tech.fragments * 20)
b.targetedNail(this.position, tech.fragments * 17)
this.endCycle = 0 //triggers despawn
}
},

View File

@@ -194,6 +194,7 @@ function collisionChecks(event) {
if (v > 9) {
let dmg = 0.075 * b.dmgScale * v * obj.mass * (tech.throwChargeRate) * (tech.isBlockHarm ? 2.5 : 1) * (tech.isMobBlockFling ? 2.5 : 1) * (tech.isBlockRestitution ? 2.5 : 1);
if (mob[k].isShielded) dmg *= 0.7
// console.log(dmg)
mob[k].damage(dmg, true);
if (tech.isBlockPowerUps && !mob[k].alive && mob[k].isDropPowerUp && m.throwCycle > m.cycle) {
let type = tech.isEnergyNoAmmo ? "heal" : "ammo"

View File

@@ -360,31 +360,31 @@ const build = {
const isCount = 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');
if (tech.tech[i].isFieldTech) {
techID.classList.remove('experiment-grid-hide');
// techID.innerHTML = `
// <div class="grid-title">
// <span style="position:relative;">
// <div class="circle-grid tech" style="position:absolute; top:0; left:0;opacity:0.8;"></div>
// <div class="circle-grid field" style="position:absolute; top:0; left:10px;opacity:0.65;"></div>
// </span>
// &nbsp; &nbsp; &nbsp; &nbsp; ${tech.tech[i].name} ${isCount}</div>${tech.tech[i].description}
// </div>`
// // <div class="circle-grid gun" style="position:absolute; top:-3px; left:-3px; opacity:1; height: 33px; width:33px;"></div>
// // <div class="circle-grid tech" style="position:absolute; top:5px; left:5px;opacity:1;height: 20px; width:20px;border: #fff solid 2px;"></div>
// // border: #fff solid 0px;
// } else if (tech.tech[i].isGunTech) {
// techID.classList.remove('experiment-grid-hide');
// techID.innerHTML = `
// <div class="grid-title">
// <span style="position:relative;">
// <div class="circle-grid tech" style="position:absolute; top:0; left:0;opacity:0.8;"></div>
// <div class="circle-grid gun" style="position:absolute; top:0; left:10px; opacity:0.65;"></div>
// </span>
// &nbsp; &nbsp; &nbsp; &nbsp; ${tech.tech[i].name} ${isCount}</div>${tech.tech[i].description}
// </div>`
// } else
techID.innerHTML = `
<div class="grid-title">
<span style="position:relative;">
<div class="circle-grid tech" style="position:absolute; top:0; left:0;opacity:0.8;"></div>
<div class="circle-grid field" style="position:absolute; top:0; left:10px;opacity:0.65;"></div>
</span>
&nbsp; &nbsp; &nbsp; &nbsp; ${tech.tech[i].name} ${isCount}</div>${tech.tech[i].description}
</div>`
// <div class="circle-grid gun" style="position:absolute; top:-3px; left:-3px; opacity:1; height: 33px; width:33px;"></div>
// <div class="circle-grid tech" style="position:absolute; top:5px; left:5px;opacity:1;height: 20px; width:20px;border: #fff solid 2px;"></div>
// border: #fff solid 0px;
} else if (tech.tech[i].isGunTech) {
techID.classList.remove('experiment-grid-hide');
techID.innerHTML = `
<div class="grid-title">
<span style="position:relative;">
<div class="circle-grid tech" style="position:absolute; top:0; left:0;opacity:0.8;"></div>
<div class="circle-grid gun" style="position:absolute; top:0; left:10px; opacity:0.65;"></div>
</span>
&nbsp; &nbsp; &nbsp; &nbsp; ${tech.tech[i].name} ${isCount}</div>${tech.tech[i].description}
</div>`
} else
if (tech.tech[i].isJunk) {
// text += `<div class="pause-grid-module"><div class="grid-title"><div class="circle-grid junk"></div> &nbsp; ${tech.tech[i].name} ${isCount}</div>${tech.tech[i].description}</div></div>`
techID.innerHTML = `<div class="grid-title"><div class="circle-grid junk"></div> &nbsp; ${tech.tech[i].name} ${isCount}</div>${tech.tech[i].description}</div>`

View File

@@ -17,7 +17,8 @@ const level = {
// simulation.isHorizontalFlipped = true
// m.setField("time dilation")
// b.giveGuns("harpoon")
// tech.giveTech("nematodes")
// tech.giveTech("filament")
// tech.giveTech("reticulum")
// tech.giveTech("necrophage")
// for (let i = 0; i < 3; i++) tech.giveTech("super sized")
// for (let i = 0; i < 9; i++) tech.giveTech("MIRV")
@@ -2280,7 +2281,7 @@ const level = {
// spawn.snakeSuckBoss(1900, -500)
// spawn.grenadier(1900, -500)
// spawn.sneaker(1900, -500)
// spawn.sneaker(1900, -500, 200)
// spawn.shield(mob[mob.length - 1], 1900, -500, 1);
// mob[mob.length - 1].isShielded = true
// spawn.historyBoss(1200, -500)
@@ -2293,11 +2294,11 @@ const level = {
// spawn.powerUpBoss(1600, -500)
// spawn.cellBossCulture(1600, -500)
// spawn.laserTargetingBoss(1600, -500)
// spawn.striker(1200, -500)
// spawn.laser(1200, -500)
spawn.nodeGroup(1200, -500, "grenadier")
// spawn.nodeGroup(1800, -500, "grenadier")
// spawn.nodeGroup(1200, 0, "grenadier")
spawn.nodeGroup(1800, -500, "grenadier")
spawn.nodeGroup(1200, 0, "grenadier")
// spawn.snakeBoss(1200, -500)

View File

@@ -530,7 +530,7 @@ const mobs = {
};
vertexCollision(this.position, look, map);
vertexCollision(this.position, look, body);
if (!m.isCloak) vertexCollision(this.position, look, [player]);
if (!m.isCloak) vertexCollision(this.position, look, [playerBody, playerHead]);
// hitting player
if (best.who === player) {
if (m.immuneCycle < m.cycle) {

View File

@@ -2125,7 +2125,8 @@ const spawn = {
};
vertexCollision(this.position, look, map);
vertexCollision(this.position, look, body);
if (!m.isCloak) vertexCollision(this.position, look, [player]);
if (!m.isCloak) vertexCollision(this.position, look, [playerBody, playerHead]);
// hitting player
if (best.who === player) {
if (m.immuneCycle < m.cycle) {
@@ -2254,8 +2255,8 @@ const spawn = {
y: this.position.y + seeRange * Math.sin(this.angle)
};
vertexCollision(this.position, look, map);
// vertexCollision(this.position, look, body);
if (!m.isCloak) vertexCollision(this.position, look, [player]);
if (!m.isCloak) vertexCollision(this.position, look, [playerBody, playerHead]);
// hitting player
if (best.who === player) {
this.targetingCount++

View File

@@ -3645,17 +3645,17 @@
}
},
{
name: "ceramic needles",
description: `<strong>needles</strong> pierce <strong>shields</strong><br>directly <strong class='color-d'>damaging</strong> shielded mobs`,
name: "ceramics",
description: `<strong>needles</strong> and <strong>harpoons</strong> pierce <strong>shields</strong><br>directly <strong class='color-d'>damaging</strong> shielded mobs`,
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return (tech.isNeedles || tech.isNeedleShot)
return tech.haveGunCheck("harpoon") || (tech.isNeedles || tech.isNeedleShot)
},
requires: "needle gun, needle-shot",
requires: "needle gun, needle-shot, harpoon",
effect() {
tech.isNeedleShieldPierce = true
},
@@ -4977,7 +4977,7 @@
},
{
name: "filament",
description: "increase the <strong>length</strong> of your <strong>harpoon</strong>'s <strong>rope</strong><br>by <strong>1%</strong> per harpoon <strong class='color-ammo'>ammo</strong>",
description: "increase the <strong>length</strong> of your <strong>harpoon</strong>'s <strong>rope</strong><br>by <strong>3%</strong> per harpoon <strong class='color-ammo'>ammo</strong>",
isGunTech: true,
maxCount: 1,
count: 0,
@@ -4996,7 +4996,7 @@
},
{
name: "unaaq",
description: "increase the <strong>length</strong> of your <strong>harpoon</strong><br>by <strong>1%</strong> per harpoon <strong class='color-ammo'>ammo</strong>",
description: "increase the <strong>length</strong> of your <strong>harpoon</strong><br>by <strong>15%</strong> of the square root of its <strong class='color-ammo'>ammo</strong>",
isGunTech: true,
maxCount: 1,
count: 0,
@@ -5013,6 +5013,25 @@
tech.isLargeHarpoon = false;
}
},
{
name: "reticulum",
description: "fire <strong>+1</strong> harpoon<br>when there are multiple targets in range",
isGunTech: true,
maxCount: 9,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return tech.haveGunCheck("harpoon")
},
requires: "harpoon",
effect() {
tech.extraHarpoons++;
},
remove() {
tech.extraHarpoons = 0;
}
},
// {
// name: "spear",
// description: "<strong>harpoons</strong> fired while <strong>crouched</strong><br>have no <strong>rope</strong> and improved <strong>steering</strong>",
@@ -8100,5 +8119,6 @@
isSmartRadius: null,
isFilament: null,
// isSpear: null,
isLargeHarpoon: null
isLargeHarpoon: null,
extraHarpoons: null
}