grappling hook 2nd update

grappling hook
  added coupling effect - 4% extra ammo per coupling
  doesn't destroy blocks, instead the player grabs blocks
  doesn't automatically retract after hitting power ups
  improved momentum conservation on yank and catching blocks, power ups
  removed accidental 55% defense for grapple field
  tech  (no images yet)
    autonomous defense - fire harpoons at nearby mobs
    rupture - explosion on impact with map, block, mob

negative mass field has horizontal block motion by default
fixed tech sorting by "allowed tech" in experiment mode
This commit is contained in:
landgreen
2023-11-25 15:26:09 -08:00
parent e9d226259e
commit ce74f420e3
8 changed files with 345 additions and 167 deletions

View File

@@ -1484,54 +1484,17 @@ const b = {
index: 3,
isInternal: false
}, {
x: 34,
y: 5,
x: 37,
y: 3,
index: 4,
isInternal: false
}],
// [{
// x: -10,
// y: 2,
// index: 0,
// isInternal: false
// }, {
// x: -10,
// y: -2,
// index: 1,
// isInternal: false
// }, {
// x: 35,
// y: -3,
// index: 2,
// isInternal: false
// }, {
// x: 37,
// y: -2,
// index: 3,
// isInternal: false
// }, {
// x: 40,
// y: 0,
// index: 4,
// isInternal: false
// }, {
// x: 37,
// y: 2,
// index: 5,
// isInternal: false
// }, {
// x: 35,
// y: 3,
// index: 6,
// isInternal: false
// }],
{
angle: angle,
friction: 1,
frictionAir: 0.4,
thrustMag: 0.13,
dmg: 6, //damage done in addition to the damage from momentum
dmg: 8, //damage done in addition to the damage from momentum
classType: "bullet",
endCycle: simulation.cycle + 70,
isSlowPull: false,
@@ -1543,6 +1506,70 @@ const b = {
// lookFrequency: Math.floor(7 + Math.random() * 3),
density: 0.004, //0.001 is normal for blocks, 0.004 is normal for harpoon, 0.004*6 when buffed
drain: 0.001,
draw() {
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))
//draw rope
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);
// if (tech.isHookWire) {
// //draw wire
// const hitMob = Matter.Query.ray(mob, this.position, m.pos, 10)
// if (hitMob.length && m.immuneCycle < m.cycle) {
// for (let i = 0; i < hitMob.length; i++) {
// console.log(hitMob[i].bodyA)
// // simulation.drawList.push({ //add dmg to draw queue
// // x: path[path.length - 1].x,
// // y: path[path.length - 1].y,
// // radius: Math.sqrt(2000 * damage * best.who.damageReduction) + 2,
// // color: tech.laserColorAlpha,
// // time: simulation.drawTime
// // });
// hitMob[i].bodyA.damage(0.001)
// }
// }
// //draw glow around wire
// ctx.strokeStyle = "rgba(0,255,255,0.2)" // "#0ce"
// ctx.lineWidth = 20
// ctx.stroke();
// }
ctx.strokeStyle = "rgba(0,255,255,0.2)" // "#0ce"
ctx.lineWidth = 10
ctx.stroke();
ctx.strokeStyle = "#000" // "#0ce"
ctx.lineWidth = 0.5
ctx.stroke();
//draw harpoon spikes
// ctx.beginPath();
// ctx.lineTo(this.vertices[3].x, this.vertices[3].y);
// // const spike1 = Vector.add(this.vertices[1], Vector.mult(Vector.sub(this.vertices[1], this.vertices[2]), 3))
// // ctx.lineTo(spike1.x, spike1.y);
// const controlPoint2 = Vector.add(this.vertices[3], Vector.mult(Vector.sub(this.vertices[3], this.vertices[2]), 20))
// ctx.quadraticCurveTo(controlPoint2.x, controlPoint2.y, this.vertices[2].x, this.vertices[2].y)
// ctx.fillStyle = '#000'
// ctx.fill();
ctx.beginPath();
ctx.lineTo(this.vertices[0].x, this.vertices[0].y);
const spikeLength = 2
// const spike1 = Vector.add(this.vertices[1], Vector.mult(Vector.sub(this.vertices[1], this.vertices[2]), spikeLength))
// ctx.moveTo(this.vertices[2].x, this.vertices[2].y);
// ctx.lineTo(spike1.x, spike1.y);
// ctx.lineTo(this.vertices[3].x, this.vertices[3].y);
const spike2 = Vector.add(this.vertices[3], Vector.mult(Vector.sub(this.vertices[3], this.vertices[2]), spikeLength))
ctx.moveTo(this.vertices[2].x, this.vertices[2].y);
ctx.lineTo(spike2.x, spike2.y);
ctx.lineTo(this.vertices[1].x, this.vertices[1].y);
ctx.fillStyle = '#000'
ctx.fill();
},
beforeDmg(who) {
if (tech.isShieldPierce && who.isShielded) { //disable shields
who.isShielded = false
@@ -1565,7 +1592,9 @@ const b = {
// // this.endCycle = 0;
// }
if (m.fieldCDcycle < m.cycle + 40) m.fieldCDcycle = m.cycle + 40 //extra long cooldown on hitting mobs
if (tech.isHookExplosion) b.explosion(this.position, 250 + 150 * Math.random()); //makes bullet do explosive damage at end
this.retract()
},
caughtPowerUp: null,
dropCaughtPowerUp() {
@@ -1594,35 +1623,6 @@ const b = {
this.dropCaughtPowerUp()
}
},
draw() {
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 harpoon spikes
const spikeLength = 2
ctx.beginPath();
const spike1 = Vector.add(this.vertices[1], Vector.mult(Vector.sub(this.vertices[1], this.vertices[2]), spikeLength))
ctx.moveTo(this.vertices[2].x, this.vertices[2].y);
ctx.lineTo(spike1.x, spike1.y);
ctx.lineTo(this.vertices[3].x, this.vertices[3].y);
const spike2 = Vector.add(this.vertices[3], Vector.mult(Vector.sub(this.vertices[3], this.vertices[2]), spikeLength))
ctx.moveTo(this.vertices[2].x, this.vertices[2].y);
ctx.lineTo(spike2.x, spike2.y);
ctx.lineTo(this.vertices[1].x, this.vertices[1].y);
ctx.fillStyle = '#000'
ctx.fill();
},
retract() {
this.do = this.returnToPlayer
this.endCycle = simulation.cycle + 60
@@ -1630,7 +1630,8 @@ const b = {
if (this.angularSpeed < 0.5) this.torque += this.inertia * 0.001 * (Math.random() - 0.5) //(Math.round(Math.random()) ? 1 : -1)
this.collisionFilter.mask = 0//cat.map | cat.mob | cat.mobBullet | cat.mobShield // | cat.body
//recoil on pulling grapple back
const momentum = Vector.mult(Vector.sub(this.velocity, player.velocity), (m.crouch ? 0.0001 : 0.0002))
const mag = this.pickUpTarget ? Math.max(this.pickUpTarget.mass, 0.5) : 0.5
const momentum = Vector.mult(Vector.sub(this.position, m.pos), mag * (m.crouch ? 0.0001 : 0.0002))
player.force.x += momentum.x
player.force.y += momentum.y
},
@@ -1642,7 +1643,20 @@ const b = {
const momentum = Vector.mult(Vector.sub(this.velocity, player.velocity), (m.crouch ? 0.0001 : 0.0002))
player.force.x += momentum.x
player.force.y += momentum.y
if (this.pickUpTarget) {
m.holdingTarget = this.pickUpTarget
// give block to player after it returns
m.isHolding = true;
//conserve momentum when player mass changes
totalMomentum = Vector.add(Vector.mult(player.velocity, player.mass), Vector.mult(Vector.normalise(this.velocity), 15 * Math.min(20, this.pickUpTarget.mass)))
Matter.Body.setVelocity(player, Vector.mult(totalMomentum, 1 / (m.defaultMass + this.pickUpTarget.mass)));
m.definePlayerMass(m.defaultMass + this.pickUpTarget.mass * m.holdingMassScale)
//make block collide with nothing
m.holdingTarget.collisionFilter.category = 0;
m.holdingTarget.collisionFilter.mask = 0;
this.pickUpTarget = null
}
} else {
if (m.energy > this.drain) m.energy -= this.drain
const sub = Vector.sub(this.position, m.pos)
@@ -1651,10 +1665,11 @@ const b = {
this.force.x -= returnForce.x
this.force.y -= returnForce.y
this.grabPowerUp()
this.grabBlocks()
}
this.draw();
},
destroyBlocks() {
destroyBlocks() {//not used?
const blocks = Matter.Query.collides(this, body)
if (blocks.length && !blocks[0].bodyA.isNotHoldable) {
if (blocks[0].bodyA.mass > 2.5) this.retract()
@@ -1679,6 +1694,32 @@ const b = {
})
}
},
pickUpTarget: null,
grabBlocks() {
if (this.pickUpTarget) {
//position block on hook
Matter.Body.setPosition(this.pickUpTarget, Vector.add(this.vertices[2], this.velocity))
Matter.Body.setVelocity(this.pickUpTarget, { x: 0, y: 0 })
} else if (!input.down) {
const blocks = Matter.Query.collides(this, body)
if (blocks.length) {
// console.log(blocks)
for (let i = 0; i < blocks.length; i++) {
if (blocks[i].bodyA.classType === "body" && !blocks[i].bodyA.isNotHoldable && !blocks[0].bodyA.mass < 60) {
this.retract()
this.pickUpTarget = blocks[i].bodyA
if (tech.isHookExplosion) b.explosion(this.position, 250 + 150 * Math.random()); //makes bullet do explosive damage at end
} else if (blocks[i].bodyB.classType === "body" && !blocks[i].bodyB.isNotHoldable && !blocks[0].bodyB.mass < 60) {
this.retract()
this.pickUpTarget = blocks[i].bodyB
if (tech.isHookExplosion) b.explosion(this.position, 250 + 150 * Math.random()); //makes bullet do explosive damage at end
}
}
// if (blocks[0].bodyA.mass > 2.5 && blocks[0].bodyA.mass > 15) {
}
}
},
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))
@@ -1695,7 +1736,7 @@ const b = {
powerUp[i].collisionFilter.mask = 0
this.thrustMag *= 0.6
this.endCycle += 0.5 //it pulls back slower, so this prevents it from ending early
this.retract()
// this.retract()
break //just pull 1 power up if possible
}
}
@@ -1706,7 +1747,8 @@ const b = {
do() {
if (m.fieldCDcycle < m.cycle + 5) m.fieldCDcycle = m.cycle + 5
if (input.field) { //&& !Matter.Query.collides(this, body).length
this.destroyBlocks()
// this.destroyBlocks()
this.grabBlocks()
this.grabPowerUp()
// if (this.endCycle < simulation.cycle + 1) { //if at end of lifespan, but player is holding down field, force retraction
// this.endCycle = simulation.cycle + 30
@@ -1736,6 +1778,7 @@ const b = {
if (input.field && Matter.Query.collides(this, map).length) {
Matter.Body.setPosition(this, Vector.add(this.position, { x: -20 * Math.cos(this.angle), y: -20 * Math.sin(this.angle) }))
if (Matter.Query.collides(this, map).length) {
if (tech.isHookExplosion) b.explosion(this.position, 150 + 50 * Math.random()); //makes bullet do explosive damage at end
Matter.Body.setVelocity(this, { x: 0, y: 0 });
Matter.Sleeping.set(this, true)
this.endCycle = simulation.cycle + 5

View File

@@ -204,6 +204,24 @@ function collisionChecks(event) {
// time: 25
// });
}
// if (true) { //fire harpoons at mobs after getting hit
// const countMax = 12
// let count = countMax
// const range = 300
// for (let i = 0; i < mob.length; i++) {
// if (count > 0 && Vector.magnitude(Vector.sub(m.pos, mob[i].position)) < range) {
// count--
// if (m.fieldCDcycle < m.cycle + 30) m.fieldCDcycle = m.cycle + 30
// const angle = Math.atan2(mob[i].position.y - player.position.y, mob[i].position.x - player.position.x);
// b.harpoon(m.pos, mob[i], angle, 0.75, true, 20) // harpoon(where, target, angle = m.angle, harpoonSize = 1, isReturn = false, totalCycles = 35, isReturnAmmo = true, thrust = 0.1) {
// for (; count > 0; count--) {
// b.harpoon(m.pos, mob[i], count * Math.PI / countMax, 0.75, true, 9) // harpoon(where, target, angle = m.angle, harpoonSize = 1, isReturn = false, totalCycles = 35, isReturnAmmo = true, thrust = 0.1) {
// bullet[bullet.length - 1].drain = 0
// }
// break
// }
// }
// }
if (tech.isStimulatedEmission) powerUps.ejectTech()
if (mob[k].onHit) mob[k].onHit();
if (m.immuneCycle < m.cycle + m.collisionImmuneCycles) m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage for 30 cycles

View File

@@ -524,12 +524,10 @@ ${simulation.isCheating ? "<br><br><em>lore disabled</em>" : ""}
if (!aHasKeyword && bHasKeyword) return 1;
return 0;
}
if (find === 'guntech') {
tech.tech.sort((a, b) => {
if (a.isGunTech && b.isGunTech) {
if (a.allowed() > b.allowed()) return -1; //sort to the top
if (!a.allowed() < b.allowed()) return 1; //sort to the bottom
return (a.allowed() === b.allowed()) ? 0 : a.allowed() ? -1 : 1;
}
if (a.isGunTech && !b.isGunTech) return -1; //sort to the top
if (!a.isGunTech && b.isGunTech) return 1; //sort to the bottom
@@ -538,30 +536,30 @@ ${simulation.isCheating ? "<br><br><em>lore disabled</em>" : ""}
} else if (find === 'fieldtech') {
tech.tech.sort((a, b) => {
if (a.isFieldTech && b.isFieldTech) {
if (a.allowed() > b.allowed()) return -1; //sort to the top
if (!a.allowed() < b.allowed()) return 1; //sort to the bottom
return (a.allowed() === b.allowed()) ? 0 : a.allowed() ? -1 : 1;
}
if (a.isFieldTech && !b.isFieldTech) return -1; //sort to the top
if (!a.isFieldTech && b.isFieldTech) return 1; //sort to the bottom
return 0;
});
} else if (find === 'allowed') {
// tech.tech.sort((a, b) => {
// if (a.allowed() > !b.allowed()) return -1; //sort to the top
// if (!a.allowed() < b.allowed()) return 1; //sort to the bottom
// return 0;
// });
tech.tech.sort((a, b) => {
if (a.allowed() > b.allowed()) return -1; //sort to the top
if (!a.allowed() < b.allowed()) return 1; //sort to the bottom
return 0;
return (a.allowed() === b.allowed()) ? 0 : a.allowed() ? -1 : 1;
});
} else if (find === 'have') {
tech.tech.sort((a, b) => {
if (a.count > b.count) return -1; //sort to the top
if (!a.count < b.count) return 1; //sort to the bottom
return (a.allowed() === b.allowed()) ? 0 : a.allowed() ? -1 : 1;
return 0;
});
} else if (find === 'heal') {
tech.tech.sort((a, b) => {
if (a.isHealTech && b.isHealTech) {
if (a.allowed() > b.allowed()) return -1; //sort to the top
if (!a.allowed() < b.allowed()) return 1; //sort to the bottom
return (a.allowed() === b.allowed()) ? 0 : a.allowed() ? -1 : 1;
}
if (a.isHealTech && !b.isHealTech) return -1; //sort to the top
if (!a.isHealTech && b.isHealTech) return 1; //sort to the bottom
@@ -570,8 +568,7 @@ ${simulation.isCheating ? "<br><br><em>lore disabled</em>" : ""}
} else if (find === 'bot') {
tech.tech.sort((a, b) => {
if (a.isBotTech && b.isBotTech) {
if (a.allowed() > b.allowed()) return -1; //sort to the top
if (!a.allowed() < b.allowed()) return 1; //sort to the bottom
return (a.allowed() === b.allowed()) ? 0 : a.allowed() ? -1 : 1;
}
if (a.isBotTech && !b.isBotTech) return -1; //sort to the top
if (!a.isBotTech && b.isBotTech) return 1; //sort to the bottom
@@ -580,8 +577,7 @@ ${simulation.isCheating ? "<br><br><em>lore disabled</em>" : ""}
} else if (document.getElementById("sort-input").value === 'skin') {
tech.tech.sort((a, b) => {
if (a.isSkin && b.isSkin) {
if (a.allowed() > b.allowed()) return -1; //sort to the top
if (!a.allowed() < b.allowed()) return 1; //sort to the bottom
return (a.allowed() === b.allowed()) ? 0 : a.allowed() ? -1 : 1;
}
if (a.isSkin && !b.isSkin) return -1; //sort to the top
if (!a.isSkin && b.isSkin) return 1; //sort to the bottom

View File

@@ -19,16 +19,18 @@ const level = {
// simulation.enableConstructMode() //tech.giveTech('motion sickness') //used to build maps in testing mode
// simulation.isHorizontalFlipped = true
// tech.giveTech("performance")
// level.difficultyIncrease(3 * 4) //30 is near max on hard //60 is near max on why
// level.difficultyIncrease(1 * 4) //30 is near max on hard //60 is near max on why
// spawn.setSpawnList();
// spawn.setSpawnList();
// m.maxHealth = m.health = 100
// m.maxEnergy = m.energy = 10000000
// tech.isRerollDamage = true
// powerUps.research.changeRerolls(99999)
// m.immuneCycle = Infinity //you can't take damage
// tech.tech[297].frequency = 100
// m.couplingChange(10)
// m.setField("grappling hook") //1 standing wave 2 perfect diamagnetism 3 negative mass 4 molecular assembler 5 plasma torch 6 time dilation 7 metamaterial cloaking 8 pilot wave 9 wormhole 10 grappling hook
// tech.isHookWire = true
// m.energy = 0
// simulation.molecularMode = 2
// m.damage(0.1);
@@ -36,10 +38,8 @@ const level = {
// b.giveGuns("harpoon") //0 nail gun 1 shotgun 2 super balls 3 wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser
// b.guns[8].ammo = 100000000
// requestAnimationFrame(() => { tech.giveTech("MACHO") });
// for (let i = 0; i < 1; ++i) tech.giveTech("electrostatic induction")
// for (let i = 0; i < 1; ++i) tech.giveTech("grappling hook")
// for (let i = 0; i < 1; ++i) tech.giveTech("superdeterminism")
// for (let i = 0; i < 1; ++i) tech.giveTech("fine-structure constant")
// for (let i = 0; i < 1; ++i) tech.giveTech("autonomous defense")
// for (let i = 0; i < 1; ++i) tech.giveTech("rupture")
// for (let i = 0; i < 1; ++i) tech.giveTech("nail-bot upgrade")
// requestAnimationFrame(() => { for (let i = 0; i < 30; i++) tech.giveTech("laser-bot") });
// for (let i = 0; i < 1; i++) tech.giveTech("laser-bot upgrade")
@@ -47,11 +47,11 @@ const level = {
// for (let i = 0; i < 1; ++i) tech.giveTech("mechanical resonance")
// for (let i = 0; i < 3; i++) powerUps.directSpawn(450, -50, "tech");
// for (let i = 0; i < 10; i++) powerUps.directSpawn(1750, -500, "research");
// for (let i = 0; i < 10; i++) powerUps.directSpawn(1750, -500, "coupling");
// for (let i = 0; i < 100; i++) powerUps.directSpawn(1750, -500, "coupling");
// level.testing();
// for (let i = 0; i < 4; ++i) spawn.hopMother(1900, -500)
// for (let i = 0; i < 0; ++i) spawn.hopper(1900, -500)
// for (let i = 0; i < 5; ++i) spawn.starter(1900, -500)
// for (let i = 0; i < 1; ++i) spawn.shooterBoss(1900, -2500)
// spawn.beetleBoss(1900, -500, 25)
// spawn.slasher2(2000, -1150)
@@ -63,7 +63,8 @@ const level = {
// for (let i = 0; i < 40; ++i) tech.giveTech()
level[simulation.isTraining ? "walk" : "intro"]() //normal starting level **************************************************
// spawn.bodyRect(2425, -120, 200, 200);
// console.log(body[body.length - 1].mass)
// simulation.isAutoZoom = false; //look in close
// simulation.zoomScale *= 0.5;
// simulation.setZoom();

View File

@@ -2496,7 +2496,6 @@ const m = {
// set pick up target for when mouse is released
if (body[grabbing.targetIndex]) {
m.holdingTarget = body[grabbing.targetIndex];
//
ctx.beginPath(); //draw on each valid body
let vertices = m.holdingTarget.vertices;
ctx.moveTo(vertices[0].x, vertices[0].y);
@@ -2588,6 +2587,8 @@ const m = {
return `<strong>+${(4 * couple).toFixed(0)}%</strong> <strong class='color-block'>block</strong> collision <strong class='color-d'>damage</strong>`
case 9: //wormhole
return `<span style = 'font-size:89%;'>after eating <strong class='color-block'>blocks</strong> <strong>+${(2 * couple).toFixed(0)}</strong> <strong class='color-f'>energy</strong></span>`
case 10: //grappling hook
return `${powerUps.orb.ammo(1)} give ${(4 * couple).toFixed(0)}% more ammo`
}
},
couplingChange(change = 0) {
@@ -2659,12 +2660,6 @@ const m = {
}
}
},
// <div id="cube" style="width: 4em; height: 8em;">
// <div style="transform: translate3d(1em, 0em, 0em)">1</div>
// <div style="transform: translate3d(2em, 0em, 0em)">2</div>
// <div style="transform: translate3d(3em, 0em, 0em)">3</div>
// <div style="transform: translate3d(4em, 0em, 0em)">4</div>
// </div>
{
name: "standing wave",
//<strong>deflecting</strong> protects you in every <strong>direction</strong>
@@ -3083,7 +3078,20 @@ const m = {
for (let i = 0, len = who.length; i < len; ++i) {
sub = Vector.sub(who[i].position, m.pos);
dist = Vector.magnitude(sub);
if (dist < range) who[i].force.y -= who[i].mass * (simulation.g * mag);
if (dist < range) {
who[i].force.y -= who[i].mass * (simulation.g * mag); //add a bit more then standard gravity
if (input.left) { //blocks move horizontally with the same force as the player
who[i].force.x -= m.FxAir * who[i].mass / 10; // move player left / a
} else if (input.right) {
who[i].force.x += m.FxAir * who[i].mass / 10; //move player right / d
}
}
// sub = Vector.sub(who[i].position, m.pos);
// dist = Vector.magnitude(sub);
// if (dist < range) who[i].force.y -= who[i].mass * (simulation.g * mag);
}
}
//control horizontal acceleration
@@ -3825,7 +3833,8 @@ const m = {
}
if (tech.isRewindField) {
this.rewindCount = 0
m.grabPowerUpRange2 = 300000
m.grabPowerUpRange2 = 300000// m.grabPowerUpRange2 = 200000;
m.hold = function () {
// console.log(m.fieldCDcycle)
m.grabPowerUp();
@@ -4944,25 +4953,64 @@ const m = {
{
name: "grappling hook",
// description: `use <strong class='color-f'>energy</strong> to pull yourself towards the <strong>map</strong><br>generate <strong>6</strong> <strong class='color-f'>energy</strong> per second`,
description: `use <strong class='color-f'>energy</strong> to fire a hook that attaches to <strong>map</strong>,<br>pulls player, <strong class='color-d'>damages</strong> mobs, and destroys <strong class='color-block'>blocks</strong><br>generate <strong>6</strong> <strong class='color-f'>energy</strong> per second`,
description: `use <strong class='color-f'>energy</strong> to fire a hook that <strong>pulls</strong> player<br><strong class='color-d'>damages</strong> mobs and destroys <strong class='color-block'>blocks</strong><br>generate <strong>6</strong> <strong class='color-f'>energy</strong> per second`,
effect: () => {
m.fieldFire = true;
// m.holdingMassScale = 0.01; //can hold heavier blocks with lower cost to jumping
m.fieldMeterColor = "#333"
m.eyeFillColor = m.fieldMeterColor
m.fieldHarmReduction = 0.45; //55% reduction
m.grabPowerUpRange2 = 300000 //m.grabPowerUpRange2 = 200000;
// m.fieldHarmReduction = 0.45; //55% reduction
m.hold = function () {
if (input.field) {
if (m.isHolding) {
m.drawHold(m.holdingTarget);
m.holding();
m.throwBlock();
} else if (input.field) {
m.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists)
if (m.fieldCDcycle < m.cycle) {
if (m.energy > 0.02) m.energy -= 0.02
const where = { x: m.pos.x + 40 * Math.cos(m.angle), y: m.pos.y + 40 * Math.sin(m.angle) }
b.grapple(where, m.angle)
b.grapple({ x: m.pos.x + 40 * Math.cos(m.angle), y: m.pos.y + 40 * Math.sin(m.angle) }, m.angle)
if (m.fieldCDcycle < m.cycle + 20) m.fieldCDcycle = m.cycle + 20
}
m.grabPowerUp();
} else {
m.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists)
if (tech.isHookDefense && m.energy > 0.33 && m.fieldCDcycle < m.cycle) {
const maxCount = 6 //scale the number of hooks fired
let count = maxCount
const range = 300
for (let i = 0; i < mob.length; i++) {
if (!mob[i].isBadTarget &&
!mob[i].isInvulnerable &&
Vector.magnitude(Vector.sub(m.pos, mob[i].position)) < range &&
Matter.Query.ray(map, m.pos, mob[i].position).length === 0
) {
count--
m.energy -= 0.2
if (m.fieldCDcycle < m.cycle + 30) m.fieldCDcycle = m.cycle + 30
const angle = Math.atan2(mob[i].position.y - player.position.y, mob[i].position.x - player.position.x);
b.harpoon(m.pos, mob[i], angle, 0.75, true, 20) // harpoon(where, target, angle = m.angle, harpoonSize = 1, isReturn = false, totalCycles = 35, isReturnAmmo = true, thrust = 0.1) {
bullet[bullet.length - 1].drain = 0
for (; count > 0; count--) {
b.harpoon(m.pos, mob[i], angle + count * 2 * Math.PI / maxCount, 0.75, true, 10)
bullet[bullet.length - 1].drain = 0
}
break
}
}
ctx.beginPath();
ctx.arc(m.pos.x, m.pos.y, range, 0, 2 * Math.PI);
ctx.strokeStyle = "#000";
ctx.lineWidth = 0.25;
ctx.setLineDash([10, 30]);
ctx.stroke();
ctx.setLineDash([]);
}
}
m.drawRegenEnergy()
//look for nearby mobs and fire harpoons at them
}
}
},

View File

@@ -621,17 +621,18 @@ const powerUps = {
return 17;
},
effect() {
const couplingExtraAmmo = m.fieldMode === 10 ? 1 + 0.04 * m.coupling : 1
if (b.inventory.length > 0) {
powerUps.animatePowerUpGrab('rgba(68, 102, 119,0.25)')
if (tech.isAmmoForGun && b.activeGun !== null) { //give extra ammo to one gun only with tech logistics
const target = b.guns[b.activeGun]
if (target.ammo !== Infinity) {
if (tech.ammoCap) {
const ammoAdded = Math.ceil(target.ammoPack * 0.7 * tech.ammoCap * 0.8) //0.7 is average
const ammoAdded = Math.ceil(target.ammoPack * 0.7 * tech.ammoCap * 0.8 * couplingExtraAmmo) //0.7 is average
target.ammo = ammoAdded
// simulation.makeTextLog(`${target.name}.<span class='color-g'>ammo</span> <span class='color-symbol'>=</span> ${ammoAdded}`)
} else {
const ammoAdded = Math.ceil((0.7 * Math.random() + 0.7 * Math.random()) * target.ammoPack * 0.8)
const ammoAdded = Math.ceil((0.7 * Math.random() + 0.7 * Math.random()) * target.ammoPack * 0.8 * couplingExtraAmmo)
target.ammo += ammoAdded
// simulation.makeTextLog(`${target.name}.<span class='color-g'>ammo</span> <span class='color-symbol'>+=</span> ${ammoAdded}`)
}
@@ -642,11 +643,12 @@ const powerUps = {
const target = b.guns[b.inventory[i]]
if (target.ammo !== Infinity) {
if (tech.ammoCap) {
const ammoAdded = Math.ceil(target.ammoPack * 0.45 * tech.ammoCap) //0.45 is average
const ammoAdded = Math.ceil(target.ammoPack * 0.45 * tech.ammoCap * couplingExtraAmmo) //0.45 is average
target.ammo = ammoAdded
// textLog += `${target.name}.<span class='color-g'>ammo</span> <span class='color-symbol'>=</span> ${ammoAdded}<br>`
} else {
const ammoAdded = Math.ceil((0.45 * Math.random() + 0.45 * Math.random()) * target.ammoPack) //Math.ceil(Math.random() * target.ammoPack)
} else { //default ammo behavior
const ammoAdded = Math.ceil((0.45 * Math.random() + 0.45 * Math.random()) * target.ammoPack * couplingExtraAmmo) //Math.ceil(Math.random() * target.ammoPack)
// console.log(ammoAdded, Math.ceil((0.45 * Math.random() + 0.45 * Math.random()) * target.ammoPack))
target.ammo += ammoAdded
// textLog += `${target.name}.<span class='color-g'>ammo</span> <span class='color-symbol'>+=</span> ${ammoAdded}<br>`
}
@@ -1270,24 +1272,25 @@ const powerUps = {
}
for (let i = 0; i < localSettings.entanglement.techIndexes.length; i++) { //add tech
let choose = localSettings.entanglement.techIndexes[i]
const isCount = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count + 1}x)` : "";
if (choose === null || tech.tech[choose].count + 1 > tech.tech[choose].maxCount || !tech.tech[choose].allowed()) {
// text += `<div class="choose-grid-module" style = "background-color: #efeff5; border: 0px; opacity:0.5; font-size: 60%; line-height: 130%; margin: 1px; padding-top: 6px; padding-bottom: 6px;"><div class="grid-title">${tech.tech[choose].name} <span style = "color: #aaa;font-weight: normal;font-size:80%;">- incoherent</span></div></div>`
text += powerUps.incoherentTechText(choose)
} else {
if (tech.tech[choose].isFieldTech) {
text += powerUps.fieldTechText(choose, `powerUps.choose('tech',${choose})`)
} else if (tech.tech[choose].isGunTech) {
text += powerUps.gunTechText(choose, `powerUps.choose('tech',${choose})`)
} else if (tech.tech[choose].isLore) {
text += `<div class="choose-grid-module" onclick="powerUps.choose('tech',${choose})"><div class="grid-title lore-text"><div class="circle-grid lore"></div> &nbsp; ${tech.tech[choose].name} ${isCount}</div>${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}</div>`
} else if (tech.tech[choose].isJunk) {
text += powerUps.junkTechText(choose, `powerUps.choose('tech',${choose})`)
} else if (tech.tech[choose].isSkin) {
text += powerUps.skinTechText(choose, `powerUps.choose('tech',${choose})`)
} else { //normal tech
text += powerUps.techText(choose, `powerUps.choose('tech',${choose})`)
if (tech.tech[choose]) {
const isCount = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count + 1}x)` : "";
if (choose === null || tech.tech[choose].count + 1 > tech.tech[choose].maxCount || !tech.tech[choose].allowed()) {
// text += `<div class="choose-grid-module" style = "background-color: #efeff5; border: 0px; opacity:0.5; font-size: 60%; line-height: 130%; margin: 1px; padding-top: 6px; padding-bottom: 6px;"><div class="grid-title">${tech.tech[choose].name} <span style = "color: #aaa;font-weight: normal;font-size:80%;">- incoherent</span></div></div>`
text += powerUps.incoherentTechText(choose)
} else {
if (tech.tech[choose].isFieldTech) {
text += powerUps.fieldTechText(choose, `powerUps.choose('tech',${choose})`)
} else if (tech.tech[choose].isGunTech) {
text += powerUps.gunTechText(choose, `powerUps.choose('tech',${choose})`)
} else if (tech.tech[choose].isLore) {
text += `<div class="choose-grid-module" onclick="powerUps.choose('tech',${choose})"><div class="grid-title lore-text"><div class="circle-grid lore"></div> &nbsp; ${tech.tech[choose].name} ${isCount}</div>${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}</div>`
} else if (tech.tech[choose].isJunk) {
text += powerUps.junkTechText(choose, `powerUps.choose('tech',${choose})`)
} else if (tech.tech[choose].isSkin) {
text += powerUps.skinTechText(choose, `powerUps.choose('tech',${choose})`)
} else { //normal tech
text += powerUps.techText(choose, `powerUps.choose('tech',${choose})`)
}
}
}
}

View File

@@ -4545,7 +4545,7 @@ const tech = {
frequency: 2,
frequencyDefault: 2,
allowed() {
return (!tech.isLargeHarpoon && tech.haveGunCheck("harpoon")) || tech.isNeedles
return (!tech.isLargeHarpoon && tech.haveGunCheck("harpoon")) || tech.isNeedles || tech.isHookDefense
},
requires: "needle gun, harpoon, not Bessemer process",
effect() {
@@ -5149,7 +5149,7 @@ const tech = {
frequency: 2,
frequencyDefault: 2,
allowed() {
return ((tech.haveGunCheck("super balls") || tech.isSuperMine) && !tech.isSuperBounce) || (tech.haveGunCheck("harpoon") && !tech.fragments)
return ((tech.haveGunCheck("super balls") || tech.isSuperMine) && !tech.isSuperBounce) || (tech.haveGunCheck("harpoon") && !tech.fragments) || tech.isHookDefense
},
requires: "super balls, harpoon, not fragmentation",
effect() {
@@ -5574,7 +5574,7 @@ const tech = {
frequency: 1,
frequencyDefault: 1,
allowed() {
return !tech.isExplodeRadio && ((tech.haveGunCheck("harpoon") && !tech.isFoamBall) || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.haveGunCheck("missiles") || (m.fieldMode === 4 && simulation.molecularMode === 1) || tech.missileBotCount || tech.isRivets || tech.blockDamage > 0.075)
return !tech.isExplodeRadio && ((tech.haveGunCheck("harpoon") && !tech.isFoamBall) || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.haveGunCheck("missiles") || (m.fieldMode === 4 && simulation.molecularMode === 1) || tech.missileBotCount || tech.isRivets || tech.blockDamage > 0.075 || tech.isHookDefense)
},
requires: "grenades, missiles, rivets, harpoon, or mass driver, not iridium-192, not polyurethane foam",
effect() {
@@ -7784,7 +7784,7 @@ const tech = {
},
{
name: "inertial mass",
description: "<strong>negative mass</strong> is larger and <strong>faster</strong><br><strong class='color-block'>blocks</strong> also move <strong>horizontally</strong> with the field",
description: "<strong>negative mass</strong> is larger and <strong>faster</strong>", //<br><strong class='color-block'>blocks</strong> also move <strong>horizontally</strong> with the field
isFieldTech: true,
maxCount: 1,
count: 0,
@@ -8052,7 +8052,7 @@ const tech = {
},
{
name: "electric generator",
description: "after <strong>deflecting</strong> mobs<br>molecular assembler generates <strong>+50</strong> <strong class='color-f'>energy</strong>",
description: "after <strong>deflecting</strong> mobs<br><strong>molecular assembler</strong> generates <strong>+50</strong> <strong class='color-f'>energy</strong>",
isFieldTech: true,
maxCount: 9,
count: 0,
@@ -8754,6 +8754,82 @@ const tech = {
tech.isWormholeMapIgnore = false
}
},
{
name: "autonomous defense",
description: "<strong>grappling hook</strong> uses <strong>20</strong> <strong class='color-f'>energy</strong><br> to fire <strong>harpoons</strong> at nearby mobs",
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return m.fieldMode === 10
},
requires: "grappling hook",
effect() {
tech.isHookDefense = true
},
remove() {
tech.isHookDefense = false
}
},
{
name: "rupture",
description: "after <strong>grappling hook</strong> impacts solid objects<br>generate an <strong class='color-e'>explosion</strong>",
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return m.fieldMode === 10
},
requires: "grappling hook",
effect() {
tech.isHookExplosion = true
},
remove() {
tech.isHookExplosion = false
}
},
// {
// name: "autonomous defense",
// description: "if you <strong>collide</strong> with a mob<br>fire <strong>harpoons</strong> at nearby mobs",
// isFieldTech: true,
// maxCount: 1,
// count: 0,
// frequency: 2,
// frequencyDefault: 2,
// allowed() {
// return m.fieldMode === 10 && !tech.isHookDefense
// },
// requires: "grappling hook, not automatic offense",
// effect() {
// tech.isHookDefense = true
// },
// remove() {
// tech.isHookDefense = false
// }
// },
// {
// name: "wire",
// description: "",
// isFieldTech: true,
// maxCount: 1,
// count: 0,
// frequency: 2,
// frequencyDefault: 2,
// allowed() {
// return m.fieldMode === 10
// },
// requires: "grappling hook",
// effect() {
// tech.isHookWire = true
// },
// remove() {
// tech.isHookWire = false
// }
// },
//**************************************************
//************************************************** experimental
//************************************************** modes
@@ -11800,4 +11876,7 @@ const tech = {
isHealBrake: null,
isMassProduction: null,
isPrinter: null,
// isHookWire: null,
isHookDefense: null,
isHookExplosion: null,
}