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:
189
js/bullet.js
189
js/bullet.js
@@ -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
|
||||
|
||||
18
js/engine.js
18
js/engine.js
@@ -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
|
||||
|
||||
28
js/index.js
28
js/index.js
@@ -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
|
||||
|
||||
17
js/level.js
17
js/level.js
@@ -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();
|
||||
|
||||
76
js/player.js
76
js/player.js
@@ -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
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -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,8 +1272,8 @@ const powerUps = {
|
||||
}
|
||||
for (let i = 0; i < localSettings.entanglement.techIndexes.length; i++) { //add tech
|
||||
let choose = localSettings.entanglement.techIndexes[i]
|
||||
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)
|
||||
@@ -1291,6 +1293,7 @@ const powerUps = {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// document.getElementById("choose-grid").classList.add("flipX");
|
||||
document.getElementById("choose-grid").innerHTML = text
|
||||
powerUps.showDraft();
|
||||
|
||||
89
js/tech.js
89
js/tech.js
@@ -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,
|
||||
}
|
||||
36
todo.txt
36
todo.txt
@@ -1,39 +1,29 @@
|
||||
******************************************************** NEXT PATCH **************************************************
|
||||
|
||||
grappling hook is now a field (work in progress)
|
||||
reworked physics to allow faster speeds, but more control
|
||||
improved rate of power up grabbing
|
||||
more player control to hook retraction rate
|
||||
changed hook shape and field image graphics
|
||||
grappling hook field coupling, more tech, bug fixes, and general polish to be added soon
|
||||
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
|
||||
|
||||
aerostat - 88->100% damage in air 22-> 25% damage on ground
|
||||
foam damage reduced 10%, ammo increased about 10%
|
||||
after hitting an invulnerable mob (drones,spores,worms,iceIX,fleas) don't die or lose cycles
|
||||
added JUNK tech: mobs! - summon 20 random mobs
|
||||
added announcement of mob names in console at start of new level
|
||||
|
||||
bug fixes
|
||||
negative mass field has horizontal block motion by default
|
||||
fixed tech sorting by "allowed tech" in experiment mode
|
||||
|
||||
*********************************************************** TODO *****************************************************
|
||||
|
||||
grappling hook is a field
|
||||
check for places that the player could get into but not out of
|
||||
maybe grapple could grab more then 1 power up?
|
||||
grapple slices blocks
|
||||
cut large blocks into 2,3
|
||||
use dead mob code for mobs > 5 sides
|
||||
write code to cut large blocks in half and remove one half
|
||||
need several field tech
|
||||
new field tech ideas
|
||||
field tech ideas
|
||||
hook and line stuns?
|
||||
increase hook damage
|
||||
hook damage aura
|
||||
hook's line does damage
|
||||
make several auto targeting harpoons after taking damage
|
||||
how to make them not drain energy
|
||||
generate ___ after destroying blocks
|
||||
energy, drones, iceIX, explosion, nails, junk bots?
|
||||
coupling effect: defense?, bonus from ammo power ups, fire rate
|
||||
|
||||
tech - killing a mob heals for the last damage you took
|
||||
disable cloaking heal? maybe you don't need to disable, just don't heal twice
|
||||
|
||||
Reference in New Issue
Block a user