diff --git a/img/CIWS.webp b/img/CIWS.webp new file mode 100644 index 0000000..2033c20 Binary files /dev/null and b/img/CIWS.webp differ diff --git a/img/autonomous defense.webp b/img/autonomous defense.webp new file mode 100644 index 0000000..3065ae8 Binary files /dev/null and b/img/autonomous defense.webp differ diff --git a/img/reel.webp b/img/reel.webp new file mode 100644 index 0000000..af2baa0 Binary files /dev/null and b/img/reel.webp differ diff --git a/img/rupture.webp b/img/rupture.webp new file mode 100644 index 0000000..8c77f01 Binary files /dev/null and b/img/rupture.webp differ diff --git a/js/bullet.js b/js/bullet.js index 57d523e..c77361f 100644 --- a/js/bullet.js +++ b/js/bullet.js @@ -1498,6 +1498,10 @@ const b = { classType: "bullet", endCycle: simulation.cycle + 70, isSlowPull: false, + drawStringControlMagnitude: 1000 + 1000 * Math.random(), + drawStringFlip: (Math.round(Math.random()) ? 1 : -1), + attached: false, + glowColor: tech.isHookExplosion ? "rgba(200,0,0,0.07)" : tech.isHarmReduce ? "rgba(50,100,255,0.1)" : "rgba(0,200,255,0.07)", collisionFilter: { category: cat.bullet, mask: tech.isShieldPierce ? cat.body | cat.mob | cat.mobBullet : cat.body | cat.mob | cat.mobBullet | cat.mobShield, @@ -1507,13 +1511,31 @@ const b = { density: 0.004, //0.001 is normal for blocks, 0.004 is normal for harpoon, 0.004*6 when buffed drain: 0.001, draw() { + // draw rope 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.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) + if (this.attached) { + const controlPoint = Vector.add(where, Vector.mult(sub, -0.5)) + ctx.quadraticCurveTo(controlPoint.x, controlPoint.y, this.vertices[0].x, this.vertices[0].y) + } else { + const long = Math.max(Vector.magnitude(sub), 60) + const perpendicular = Vector.mult(Vector.normalise(Vector.perp(sub)), this.drawStringFlip * Math.min(0.7 * long, 10 + this.drawStringControlMagnitude / (10 + Vector.magnitude(sub)))) + const controlPoint = Vector.add(Vector.add(where, Vector.mult(sub, -0.5)), perpendicular) + 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(); + ctx.strokeStyle = this.glowColor // "#0ce" + ctx.lineWidth = 10 + ctx.stroke(); + ctx.strokeStyle = "#000" // "#0ce" + ctx.lineWidth = 0.5 + ctx.stroke(); + // ctx.lineTo(this.vertices[0].x, this.vertices[0].y); // if (tech.isHookWire) { // //draw wire @@ -1536,36 +1558,16 @@ const b = { // 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(); - + //draw hook 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)) + const spike = Vector.add(this.vertices[3], Vector.mult(Vector.sub(this.vertices[3], this.vertices[2]), 2)) ctx.moveTo(this.vertices[2].x, this.vertices[2].y); - ctx.lineTo(spike2.x, spike2.y); + ctx.lineTo(spike.x, spike.y); ctx.lineTo(this.vertices[1].x, this.vertices[1].y); ctx.fillStyle = '#000' ctx.fill(); @@ -1577,24 +1579,9 @@ const b = { who.isShielded = true }); } - // if (tech.fragments) { - // b.targetedNail(this.vertices[2], tech.fragments * Math.floor(2 + Math.random())) - // } - // if (tech.isFoamBall) { - // for (let i = 0, len = 3 * this.mass; i < len; i++) { - // const radius = 5 + 8 * Math.random() - // const velocity = { - // x: Math.max(0.5, 2 - radius * 0.1), - // y: 0 - // } - // b.foam(this.position, Vector.rotate(velocity, 6.28 * Math.random()), radius) - // } - // // 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() { @@ -1624,6 +1611,7 @@ const b = { } }, retract() { + this.attached = false this.do = this.returnToPlayer this.endCycle = simulation.cycle + 60 Matter.Body.setDensity(this, 0.0005); //reduce density on return @@ -1644,6 +1632,17 @@ const b = { player.force.x += momentum.x player.force.y += momentum.y if (this.pickUpTarget) { + if (tech.isReel && this.blockDist > 150) { + // console.log(0.0003 * Math.min(this.blockDist, 1000)) + m.energy += 0.00044 * Math.min(this.blockDist, 800) //max 0.352 energy + simulation.drawList.push({ //add dmg to draw queue + x: m.pos.x, + y: m.pos.y, + radius: 10, + color: m.fieldMeterColor, + time: simulation.drawTime + }); + } m.holdingTarget = this.pickUpTarget // give block to player after it returns m.isHolding = true; @@ -1696,22 +1695,46 @@ const b = { }, pickUpTarget: null, grabBlocks() { - if (this.pickUpTarget) { + if (this.pickUpTarget) { //if always attached to a block //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) { + } 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 + if (tech.isHookExplosion) { + b.explosion(this.position, 250 + 150 * Math.random()); //makes bullet do explosive damage at end + const blockVertices = blocks[i].bodyA.vertices + Composite.remove(engine.world, blocks[i].bodyA) + body.splice(body.indexOf(blocks[i].bodyA), 1) + //animate the block fading away + simulation.ephemera.push({ + name: "blockFadeOut", + count: 25, //cycles before it self removes + do() { + this.count-- + if (this.count < 0) simulation.removeEphemera(this.name) + ctx.beginPath(); + ctx.moveTo(blockVertices[0].x, blockVertices[0].y); + for (let j = 1; j < blockVertices.length; j++) ctx.lineTo(blockVertices[j].x, blockVertices[j].y); + ctx.lineTo(blockVertices[0].x, blockVertices[0].y); + ctx.lineWidth = 2; + ctx.strokeStyle = `rgba(0,0,0,${this.count / 25})` + ctx.stroke(); + }, + }) + } else { + this.pickUpTarget = blocks[i].bodyA + this.blockDist = Vector.magnitude(Vector.sub(this.pickUpTarget.position, m.pos)) + } } else if (blocks[i].bodyB.classType === "body" && !blocks[i].bodyB.isNotHoldable && !blocks[0].bodyB.mass < 60) { this.retract() this.pickUpTarget = blocks[i].bodyB + this.blockDist = Vector.magnitude(Vector.sub(this.pickUpTarget.position, m.pos)) if (tech.isHookExplosion) b.explosion(this.position, 250 + 150 * Math.random()); //makes bullet do explosive damage at end } } @@ -1779,6 +1802,7 @@ const b = { 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 + this.attached = true Matter.Body.setVelocity(this, { x: 0, y: 0 }); Matter.Sleeping.set(this, true) this.endCycle = simulation.cycle + 5 @@ -1802,14 +1826,15 @@ const b = { if (input.down) { //down this.isSlowPull = true dist = 0 - player.force.y += 2.5 * player.mass * simulation.g; //adjust this to control fall rate while hooked and pressing down + player.force.y += 3 * player.mass * simulation.g; //adjust this to control fall rate while hooked and pressing down } else if (input.up) { this.isSlowPull = false + player.force.y -= player.mass * simulation.g; //adjust this to control fall rate while hooked and pressing down } if (m.energy < this.drain) this.isSlowPull = true // pulling friction that allowed a slight swinging, but has high linear pull at short dist - const drag = 1 - 30 / Math.min(Math.max(100, dist), 700) - 0.1 * (player.speed > 70) + const drag = 1 - 30 / Math.min(Math.max(100, dist), 700) - 0.1 * (player.speed > 66) // console.log(player.speed) Matter.Body.setVelocity(player, { x: player.velocity.x * drag, y: player.velocity.y * drag }); const pullScale = 0.0004 diff --git a/js/engine.js b/js/engine.js index 0374fcd..c3813d1 100644 --- a/js/engine.js +++ b/js/engine.js @@ -204,24 +204,17 @@ 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.isHarpoonDefense) { //fire harpoons at mobs after getting hit + const maxCount = 10 + 3 * tech.extraHarpoons //scale the number of hooks fired + let count = maxCount - 1 + const angle = Math.atan2(mob[k].position.y - player.position.y, mob[k].position.x - player.position.x); + b.harpoon(m.pos, mob[k], angle, 0.75, true, 7) // 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[k], angle + count * 2 * Math.PI / maxCount, 0.75, true, 7) + bullet[bullet.length - 1].drain = 0 + } + } 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 diff --git a/js/index.js b/js/index.js index 54eff25..b6a8552 100644 --- a/js/index.js +++ b/js/index.js @@ -1275,7 +1275,7 @@ window.addEventListener("keydown", function (event) { simulation.molecularMode++ m.fieldUpgrades[4].description = m.fieldUpgrades[4].setDescription() } else { - m.setField((m.fieldMode === m.fieldUpgrades.length - 1) ? 0 : m.fieldMode + 1) //cycle to next field + m.setField((m.fieldMode === m.fieldUpgrades.length - 1) ? 1 : m.fieldMode + 1) //cycle to next field, skip field emitter if (m.fieldMode === 4) { simulation.molecularMode = 0 m.fieldUpgrades[4].description = m.fieldUpgrades[4].setDescription() diff --git a/js/level.js b/js/level.js index 3f1401f..ff380f1 100644 --- a/js/level.js +++ b/js/level.js @@ -11,7 +11,7 @@ const level = { // playableLevels: ["pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion"], //see level.populateLevels: (intro, ... , reservoir or factory, reactor, ... , subway, final) added later playableLevels: ["labs", "rooftops", "skyscrapers", "warehouse", "highrise", "office", "aerie", "satellite", "sewers", "testChamber", "pavilion", "lock"], - communityLevels: ["gauntlet", "stronghold", "basement", "crossfire", "vats", "run", "ngon", "house", "perplex", "coliseum", "tunnel", "islands", "temple", "dripp", "biohazard", "stereoMadness", "yingYang", "staircase", "fortress", "commandeer", "clock", "buttonbutton", "downpour", "superNgonBros", "underpass", "cantilever", "tlinat", "ruins", "ace", "crimsonTowers", "LaunchSite"], + communityLevels: ["gauntlet", "stronghold", "basement", "crossfire", "vats", "run", "ngon", "house", "perplex", "coliseum", "tunnel", "islands", "temple", "dripp", "biohazard", "stereoMadness", "yingYang", "staircase", "fortress", "commandeer", "clock", "buttonbutton", "downpour", "superNgonBros", "underpass", "cantilever", "tlinat", "ruins", "ace", "crimsonTowers", "LaunchSite", "shipwreck"], trainingLevels: ["walk", "crouch", "jump", "hold", "throw", "throwAt", "deflect", "heal", "fire", "nailGun", "shotGun", "superBall", "matterWave", "missile", "stack", "mine", "grenades", "harpoon", "diamagnetism"], levels: [], start() { @@ -19,7 +19,7 @@ const level = { // simulation.enableConstructMode() //tech.giveTech('motion sickness') //used to build maps in testing mode // simulation.isHorizontalFlipped = true // tech.giveTech("performance") - // level.difficultyIncrease(1 * 4) //30 is near max on hard //60 is near max on why + // level.difficultyIncrease(5 * 4) //30 is near max on hard //60 is near max on why // spawn.setSpawnList(); // spawn.setSpawnList(); // m.maxHealth = m.health = 100 @@ -38,25 +38,26 @@ 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("autonomous defense") - // for (let i = 0; i < 1; ++i) tech.giveTech("rupture") - // for (let i = 0; i < 1; ++i) tech.giveTech("nail-bot upgrade") + // for (let i = 0; i < 1; ++i) tech.giveTech("degenerate matter") + // for (let i = 0; i < 1; ++i) tech.giveTech("reel") + // for (let i = 0; i < 1; ++i) tech.giveTech("tokamak") // requestAnimationFrame(() => { for (let i = 0; i < 30; i++) tech.giveTech("laser-bot") }); // for (let i = 0; i < 1; i++) tech.giveTech("laser-bot upgrade") - // for (let i = 0; i < 1; ++i) tech.giveTech("uncertainty principle") - // for (let i = 0; i < 1; ++i) tech.giveTech("mechanical resonance") + // for (let i = 0; i < 1; ++i) tech.giveTech("rupture") + // for (let i = 0; i < 1; ++i) tech.giveTech("autonomous defense") // 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 < 100; i++) powerUps.directSpawn(1750, -500, "coupling"); - // level.testing(); + // level.shipwreck(); + // for (let i = 0; i < 4; ++i) spawn.hopMother(1900, -500) // for (let i = 0; i < 5; ++i) spawn.starter(1900, -500) - // for (let i = 0; i < 1; ++i) spawn.shooterBoss(1900, -2500) + // for (let i = 0; i < 1; ++i) spawn.timeSkipBoss(1900, -2500) // spawn.beetleBoss(1900, -500, 25) // spawn.slasher2(2000, -1150) // spawn.zombie(-3000, -500 + 300 * Math.random(), 30, 5, "white") // zombie(x, y, radius, sides, color) - // for (let i = 0; i < 20; ++i) spawn.starter(1000 + 1000 * Math.random(), -500 + 300 * Math.random()) + // for (let i = 0; i < 5; ++i) spawn.starter(1000 + 1000 * Math.random(), -500 + 300 * Math.random()) // tech.addJunkTechToPool(2) // tech.tech[322].frequency = 100 // spawn.tetherBoss(1900, -500, { x: 1900, y: -500 }) @@ -29768,6 +29769,319 @@ const level = { // spawn.secondaryBossChance(100, -1500) powerUps.addResearchToLevel() //needs to run after mobs are spawned }, + shipwreck() { + simulation.makeTextLog(`shipwreck by 3xionDev`); + level.setPosToSpawn(0, -50); //normal spawn + level.exit.x = 1500; + level.exit.y = -1875; + spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); //bump for level entrance + spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20); //bump for level exit + level.defaultZoom = 1800 + simulation.zoomTransition(level.defaultZoom) + document.body.style.backgroundColor = "#05001C"; + // color.map = "#444" //custom map color + spawn.mapRect(-325, 0, 650, 300); + spawn.mapRect(-275, -675, 50, 700); + spawn.mapRect(-325, -1025, 650, 300); + spawn.mapRect(-275, -750, 50, 75); + spawn.mapRect(300, 50, 675, 200); + spawn.mapRect(925, 50, 450, 150); + spawn.mapRect(275, -750, 50, 275); + spawn.mapRect(275, -325, 50, 325); + spawn.bodyRect(150, -175, 100, 100); + spawn.bodyRect(-200, -450, 100, 400); + spawn.bodyRect(-150, -650, 25, 50); + spawn.bodyRect(-200, -700, 25, 25); + spawn.bodyRect(175, -250, 75, 100); + spawn.mapRect(875, -50, 100, 100); + spawn.mapRect(350, -175, 25, 25); + spawn.mapRect(325, -175, 175, 225); + spawn.bodyRect(375, -225, 50, 50); + spawn.bodyRect(700, -450, 125, 125); + spawn.mapRect(1375, 25, 400, 100); + spawn.mapRect(1675, -175, 100, 200); + spawn.mapRect(1775, -175, 225, 100); + spawn.mapRect(1575, -75, 100, 100); + spawn.mapRect(1775, -75, 175, 100); + spawn.mapRect(1300, 125, 250, 25); + spawn.mapRect(850, 200, 225, 25); + spawn.mapRect(1100, 200, 50, 100); + spawn.mapRect(1250, 175, 50, 125); + spawn.mapRect(1950, -150, 275, 50); + spawn.mapRect(2125, -150, 25, 25); + spawn.mapRect(2125, -175, 1025, 100); + spawn.mapRect(2625, -350, 25, 25); + spawn.mapRect(2650, -325, 25, 150); + spawn.mapRect(2625, -400, 50, 250); + spawn.bodyRect(1900, -200, 325, 25); + spawn.bodyRect(2525, -275, 100, 100); + spawn.bodyRect(2575, -325, 50, 50); + spawn.mapRect(425, -75, 150, 125); + spawn.bodyRect(350, -250, 75, 75); + spawn.bodyRect(1250, -200, 25, 25); + spawn.bodyRect(1150, -350, 100, 175); + spawn.bodyRect(1375, -375, 25, 25); + spawn.bodyRect(1375, -400, 50, 100); + spawn.mapRect(2650, -400, 500, 50); + spawn.mapRect(3100, -175, 300, 50); + spawn.bodyRect(2700, -250, 75, 25); + spawn.bodyRect(2725, -275, 25, 25); + spawn.bodyRect(2750, -250, 25, 25); + spawn.bodyRect(2825, -275, 75, 100); + spawn.randomMob(3650, -250, 0); + spawn.bodyRect(2925, -225, 50, 50); + spawn.mapRect(325, -950, 25, 25); + spawn.mapRect(325, -975, 650, 200); + spawn.mapRect(975, -900, 200, 100); + spawn.mapRect(1175, -850, 100, 100); + spawn.mapRect(1275, -800, 75, 125); + spawn.mapRect(1350, -725, 25, 125); + spawn.mapRect(1225, -800, 25, 25); + spawn.mapRect(950, -925, 100, 25); + spawn.mapRect(1150, -875, 100, 25); + spawn.mapRect(1250, -825, 75, 50); + spawn.mapRect(1125, -825, 75, 50); + spawn.mapRect(1250, -775, 50, 50); + spawn.mapRect(1400, -225, 100, 200); + spawn.mapRect(1550, -150, 125, 75); + spawn.mapRect(1500, -100, 75, 75); + spawn.mapRect(1175, -225, 225, 100); + spawn.mapRect(1475, -200, 100, 100); + spawn.mapRect(1300, -175, 125, 100); + spawn.mapRect(1250, -150, 50, 200); + spawn.mapRect(1600, -275, 50, 150); + spawn.mapRect(1300, -275, 75, 75); + spawn.mapRect(1475, -375, 50, 225); + spawn.mapRect(1575, -225, 25, 100); + spawn.mapRect(1500, -325, 50, 125); + spawn.bodyRect(1400, -350, 25, 50); + spawn.bodyRect(1650, -425, 50, 50); + spawn.bodyRect(1750, -475, 25, 125); + spawn.bodyRect(1725, -575, 150, 50); + spawn.bodyRect(1625, -425, 25, 50); + spawn.bodyRect(1175, -425, 75, 75); + spawn.mapRect(325, -625, 175, 50); + spawn.mapRect(425, -800, 25, 175); + spawn.mapRect(375, -800, 25, 200); + spawn.mapRect(500, -800, 25, 225); + spawn.mapRect(475, -800, 50, 225); + spawn.mapRect(675, -875, 50, 575); + spawn.mapRect(675, -150, 25, 175); + spawn.mapRect(700, -150, 25, 75); + spawn.mapRect(675, -125, 25, 200); + spawn.bodyRect(675, -300, 50, 150); + spawn.mapRect(2125, -1025, 1025, 100); + spawn.mapRect(3050, -975, 325, 50); + spawn.mapRect(3300, -925, 75, 600); + spawn.bodyRect(3300, -325, 75, 125); + spawn.bodyRect(3325, -325, 25, 25); + spawn.mapRect(3300, -325, 75, 25); + spawn.mapRect(3325, -175, 1100, 25); + spawn.mapRect(3325, -950, 1100, 25); + spawn.mapRect(3350, -725, 225, 25); + spawn.mapRect(3500, -925, 75, 200); + spawn.mapRect(3350, -850, 175, 25); + spawn.bodyRect(4075, -625, 125, 125); + spawn.bodyRect(3850, -825, 75, 50); + spawn.bodyRect(4050, -800, 25, 50); + spawn.bodyRect(4150, -825, 75, 100); + spawn.bodyRect(3900, -800, 50, 75); + spawn.bodyRect(3575, -375, 100, 75); + spawn.bodyRect(3800, -675, 75, 100); + spawn.bodyRect(3950, -875, 250, 150); + spawn.bodyRect(3975, -700, 50, 100); + spawn.bodyRect(4150, -775, 200, 125); + spawn.bodyRect(3825, -700, 50, 125); + spawn.bodyRect(3575, -550, 125, 50); + spawn.bodyRect(3750, -550, 25, 25); + spawn.bodyRect(3600, -625, 75, 50); + spawn.bodyRect(3550, -500, 75, 50); + spawn.bodyRect(4200, -675, 75, 75); + spawn.bodyRect(4400, -600, 50, 125); + spawn.mapRect(4375, -175, 350, 25); + spawn.mapRect(4475, -200, 475, 50); + spawn.mapRect(4450, -925, 25, 25); + spawn.mapRect(4475, -950, 475, 50); + spawn.mapRect(4350, -950, 225, 25); + spawn.mapRect(4450, -925, 100, 750); + spawn.mapRect(4650, -900, 825, 700); + spawn.mapRect(5250, -825, 475, 550); + spawn.mapRect(5550, -725, 700, 350); + spawn.mapRect(6100, -625, 550, 150); + spawn.mapRect(6600, -575, 225, 50); + spawn.mapRect(1325, -875, 50, 200); + spawn.mapRect(1275, -825, 50, 25); + spawn.mapRect(1275, -875, 25, 50); + spawn.mapRect(1225, -900, 75, 25); + spawn.mapRect(1325, -900, 50, 75); + spawn.mapRect(1075, -925, 200, 75); + spawn.mapRect(1275, -975, 75, 150); + spawn.mapRect(1300, -800, 100, 150); + spawn.mapRect(1375, -725, 50, 150); + spawn.mapRect(-325, -1525, 650, 300); + spawn.mapRect(150, -1275, 50, 375); + spawn.mapRect(-100, -1350, 50, 450); + spawn.mapRect(-325, -2600, 650, 300); + spawn.mapRect(-275, -2400, 25, 50); + spawn.mapRect(-275, -2325, 50, 825); + spawn.mapRect(300, -1475, 675, 200); + spawn.bodyRect(375, -1250, 75, 75); + spawn.bodyRect(800, -1275, 25, 300); + spawn.mapRect(1950, -1000, 175, 100); + spawn.mapRect(1850, -950, 125, 125); + spawn.mapRect(1825, -875, 75, 125); + spawn.mapRect(1825, -800, 25, 125); + spawn.mapRect(1800, -750, 25, 150); + spawn.mapRect(1775, -625, 50, 150); + spawn.mapRect(2000, -900, 25, 225); + spawn.mapRect(2075, -925, 50, 400); + spawn.mapRect(1000, -825, 25, 300); + spawn.mapRect(1050, -900, 50, 25); + spawn.mapRect(1050, -925, 50, 25); + spawn.mapRect(2475, -100, 50, 350); + spawn.mapRect(2650, -100, 25, 725); + spawn.mapRect(2350, -950, 50, 350); + spawn.mapRect(775, -825, 25, 375); + spawn.mapRect(3750, -950, 25, 175); + spawn.mapRect(3625, -925, 25, 275); + spawn.mapRect(4225, -925, 50, 200); + spawn.mapRect(950, -1425, 200, 100); + spawn.mapRect(1150, -1400, 150, 75); + spawn.mapRect(1300, -1350, 25, 100); + spawn.mapRect(1275, -1350, 25, 50); + spawn.bodyRect(1300, -1250, 25, 275); + spawn.bodyRect(2600, -1575, 375, 550); + spawn.bodyRect(2625, -1300, 75, 150); + spawn.bodyRect(2700, -1475, 100, 275); + spawn.bodyRect(2525, -1200, 75, 150); + spawn.mapRect(1675, -1400, 200, 75); + spawn.mapRect(1825, -1425, 225, 100); + spawn.mapRect(1650, -1350, 75, 100); + spawn.mapRect(1700, -1275, 25, 125); + spawn.bodyRect(1225, -1425, 550, 25); + spawn.bodyRect(1300, -1650, 100, 150); + spawn.bodyRect(1600, -1675, 100, 200); + spawn.bodyRect(1575, -1525, 25, 25); + spawn.bodyRect(1450, -1575, 25, 125); + spawn.bodyRect(1500, -1650, 75, 50); + spawn.mapRect(2325, -1225, 50, 200); + spawn.mapRect(2375, -1300, 100, 275); + spawn.mapRect(2225, -1125, 125, 100); + spawn.mapRect(2300, -1150, 50, 50); + spawn.bodyRect(2250, -850, 75, 100); + spawn.mapRect(150, -2550, 800, 200); + spawn.mapRect(875, -2500, 275, 100); + spawn.mapRect(325, -2400, 75, 375); + spawn.mapRect(325, -1800, 75, 350); + spawn.bodyRect(325, -2025, 75, 225); + spawn.mapRect(-150, -2375, 25, 375); + spawn.mapRect(25, -2400, 50, 500); + spawn.mapRect(-100, -2375, 25, 225); + spawn.mapRect(200, -2350, 50, 250); + spawn.bodyRect(250, -1875, 25, 75); + spawn.bodyRect(-50, -2050, 50, 50); + spawn.mapRect(1050, -1350, 50, 150); + spawn.mapRect(575, -1325, 25, 100); + spawn.mapRect(400, -1300, 25, 75); + spawn.mapRect(525, -1300, 50, 125); + spawn.mapRect(575, -2400, 75, 275); + spawn.mapRect(650, -2325, 25, 325); + spawn.mapRect(625, -2150, 50, 75); + spawn.mapRect(625, -2375, 50, 100); + spawn.mapRect(600, -2125, 25, 25); + spawn.mapRect(650, -2075, 25, 150); + spawn.mapRect(675, -2375, 50, 200); + spawn.mapRect(650, -2200, 50, 75); + spawn.mapRect(625, -2100, 50, 75); + spawn.mapRect(1100, -2475, 950, 50); + spawn.mapRect(1325, -1825, 450, 25); + spawn.mapRect(1475, -1850, 150, 50); + spawn.mapRect(1725, -2425, 50, 600); + spawn.mapRect(1325, -2450, 50, 450); + spawn.mapRect(1475, -2425, 25, 150); + spawn.mapRect(1675, -2425, 25, 600); + spawn.bodyRect(1450, -2175, 50, 75); + spawn.bodyRect(1650, -2200, 50, 50); + spawn.mapRect(950, -1550, 75, 125); + spawn.mapRect(900, -1500, 50, 50); + spawn.mapRect(2000, -2475, 125, 50); + spawn.mapRect(2100, -2475, 1050, 100); + spawn.mapRect(3050, -2425, 300, 50); + spawn.mapRect(3225, -2400, 1350, 25); + spawn.mapRect(4475, -2400, 475, 50); + spawn.mapRect(4900, -2375, 1125, 50); + spawn.mapRect(3950, -1350, 2075, 50); + spawn.mapRect(4075, -1325, 75, 400); + spawn.mapRect(4775, -1325, 75, 425); + spawn.mapRect(6000, -2350, 1075, 1025); + spawn.mapRect(6675, -2250, 950, 825); + spawn.mapRect(7375, -2050, 700, 425); + spawn.mapRect(7850, -1900, 425, 125); + spawn.mapRect(8200, -1850, 275, 25); + spawn.mapRect(5000, -2350, 75, 400); + spawn.mapRect(5200, -2350, 25, 600); + spawn.mapRect(5600, -2325, 25, 475); + spawn.mapRect(5750, -2350, 50, 300); + spawn.mapRect(5800, -2325, 25, 400); + spawn.mapRect(5775, -2075, 25, 50); + spawn.bodyRect(5325, -2250, 75, 125); + spawn.bodyRect(5925, -1800, 75, 125); + spawn.bodyRect(5475, -1800, 75, 225); + spawn.bodyRect(5350, -2050, 175, 100); + spawn.bodyRect(5475, -2125, 75, 125); + spawn.bodyRect(5750, -1750, 100, 100); + spawn.bodyRect(5900, -1950, 175, 150); + spawn.bodyRect(4600, -1950, 150, 275); + spawn.bodyRect(4875, -1875, 150, 100); + spawn.mapRect(5675, -1600, 350, 50); + spawn.mapRect(4325, -1300, 25, 200); + spawn.mapRect(3975, -2375, 75, 350); + spawn.mapRect(4250, -2375, 25, 550); + spawn.mapRect(2875, -2400, 75, 400); + spawn.mapRect(3050, -2425, 25, 700); + spawn.mapRect(2450, -2425, 75, 550); + spawn.mapRect(3375, -2375, 25, 525); + spawn.mapRect(3325, -1125, 75, 225); + spawn.mapRect(3125, -1200, 25, 200); + spawn.mapRect(2975, -1225, 75, 225); + spawn.mapRect(1875, -2425, 50, 550); + spawn.mapRect(1900, -1925, 475, 50); + spawn.mapRect(2300, -2400, 75, 475); + spawn.bodyRect(2025, -2325, 50, 50); + spawn.bodyRect(2150, -2300, 100, 100); + spawn.bodyRect(2025, -2325, 25, 100); + spawn.bodyRect(2125, -2275, 75, 75); + spawn.bodyRect(2250, -2250, 25, 50); + spawn.bodyRect(2000, -2325, 75, 100); + spawn.bodyRect(2150, -2300, 75, 100); + spawn.bodyRect(1975, -2300, 75, 75); + spawn.bodyRect(2150, -2300, 75, 75); + spawn.bodyRect(2025, -2350, 50, 125); + spawn.bodyRect(2250, -2325, 50, 75); + spawn.randomMob(2625, -750, 0); + spawn.randomMob(3200, -725, 0); + spawn.randomMob(2900, -575, 0); + spawn.randomMob(700, -1100, 0); + spawn.randomMob(3275, -1575, 0); + spawn.randomMob(3950, -1500, 0); + spawn.randomMob(3725, -1300, 0); + spawn.randomMob(3625, -1700, 0); + spawn.randomMob(2250, -1675, 0); + spawn.randomMob(550, -1875, 0); + spawn.randomMob(1600, -700, 0); + spawn.randomMob(1050, -400, 0); + spawn.randomSmallMob(1085, -1591); + spawn.randomSmallMob(1516, -532); + spawn.randomGroup(1551, -466, 0.4); + if (simulation.difficulty > 1) spawn.randomLevelBoss(3928, -655); + spawn.secondaryBossChance(4088, -1744) + + level.custom = () => { + level.exit.drawAndCheck(); + + level.enter.draw(); + }; + }, // ******************************************************************************************************** // ******************************************************************************************************** // ***************************************** training levels ********************************************** diff --git a/js/mob.js b/js/mob.js index 986f725..d86b9fc 100644 --- a/js/mob.js +++ b/js/mob.js @@ -1193,6 +1193,11 @@ const mobs = { this.alive = false; //triggers mob removal in mob[i].replace(i) if (this.isDropPowerUp) { + // if (true) { + // //killing a mob heals for the last damage you took + + + // } if (this.isSoonZombie) { //spawn zombie on death this.leaveBody = false; let count = 5 //delay spawn cycles diff --git a/js/player.js b/js/player.js index 459438c..82bc338 100644 --- a/js/player.js +++ b/js/player.js @@ -568,8 +568,8 @@ const m = { if (tech.squirrelFx !== 1) dmg *= 0.78//Math.pow(0.78, (tech.squirrelFx - 1) / 0.4) if (tech.isAddBlockMass && m.isHolding) dmg *= 0.1 if (tech.isSpeedHarm && player.speed > 0.1) dmg *= 1 - Math.min(player.speed * 0.0165, 0.66) - if (tech.isHarmReduce && input.field) dmg *= 0.25 - if (tech.isNeutronium && input.field && m.fieldCDcycle < m.cycle) dmg *= 0.1 + if (tech.isHarmReduce && input.field) dmg *= 0.15 + if (tech.isNeutronium && input.field && m.fieldCDcycle < m.cycle) dmg *= 0.05 if (tech.isBotArmor) dmg *= 0.94 ** b.totalBots() if (tech.isHarmArmor && m.lastHarmCycle + 600 > m.cycle) dmg *= 0.33; if (tech.isNoFireDefense && m.cycle > m.fireCDcycle + 120) dmg *= 0.3 @@ -2043,7 +2043,9 @@ const m = { } }, setFieldRegen() { - if (m.fieldMode === 6) { + if (m.fieldMode === 0) { + m.fieldRegen = 0.00067 //4 energy per second for field emitter + } else if (m.fieldMode === 6) { m.fieldRegen = 0.002 //12 energy per second for time dilation } else if (m.fieldMode === 2) { m.fieldRegen = 0.000833 //5 energy per second perfect dia @@ -2636,7 +2638,7 @@ const m = { name: "field emitter", imageNumber: Math.floor(Math.random() * 23), description: `initial field
use energy to deflect mobs and throw blocks -
generate 6 energy per second`, //
100 max energy +
generate 4 energy per second`, //
100 max energy effect: () => { m.hold = function () { if (m.isHolding) { @@ -4957,7 +4959,7 @@ const m = { effect: () => { m.fieldFire = true; // m.holdingMassScale = 0.01; //can hold heavier blocks with lower cost to jumping - m.fieldMeterColor = "#333" + // m.fieldMeterColor = "#789"//"#456" m.eyeFillColor = m.fieldMeterColor m.grabPowerUpRange2 = 300000 //m.grabPowerUpRange2 = 200000; // m.fieldHarmReduction = 0.45; //55% reduction diff --git a/js/powerup.js b/js/powerup.js index 6ffd71b..f481842 100644 --- a/js/powerup.js +++ b/js/powerup.js @@ -621,7 +621,7 @@ const powerUps = { return 17; }, effect() { - const couplingExtraAmmo = m.fieldMode === 10 ? 1 + 0.04 * m.coupling : 1 + const couplingExtraAmmo = (m.fieldMode === 10 || m.fieldMode === 0) ? 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 diff --git a/js/spawn.js b/js/spawn.js index fe8834b..cb45c95 100644 --- a/js/spawn.js +++ b/js/spawn.js @@ -7236,6 +7236,7 @@ const spawn = { m.walk_cycle += m.flipLegs * m.Vx //makes the legs look like they are moving fast + // if (simulation.fpsCap > 999){} ctx.beginPath(); ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI); ctx.fillStyle = "#fff"; diff --git a/js/tech.js b/js/tech.js index 2c835f9..963939c 100644 --- a/js/tech.js +++ b/js/tech.js @@ -218,7 +218,7 @@ const tech = { } }, hasExplosiveDamageCheck() { - return tech.haveGunCheck("missiles") || (m.fieldMode === 4 && simulation.molecularMode === 1) || tech.missileBotCount > 0 || tech.isBoomBotUpgrade || tech.isIncendiary || tech.isPulseLaser || tech.isTokamak || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) + return tech.haveGunCheck("missiles") || (m.fieldMode === 4 && simulation.molecularMode === 1) || tech.missileBotCount > 0 || tech.isBoomBotUpgrade || tech.isIncendiary || tech.isPulseLaser || tech.isTokamak || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.isHookExplosion }, damage: 1, //used for tech changes to player damage that don't have complex conditions damageFromTech() { @@ -232,7 +232,7 @@ const tech = { // } // } if (tech.isDivisor && b.activeGun && b.guns[b.activeGun].ammo % 3 === 0) dmg *= 1.77 - if (tech.isNoGroundDamage) dmg *= m.onGround ? 0.75 : 2 + if (tech.isNoGroundDamage) dmg *= m.onGround ? 0.85 : 2 if (tech.isDilate) dmg *= 1.5 + 0.6 * Math.sin(m.cycle * 0.0075) if (tech.isGunChoice && tech.buffedGun === b.inventoryGun) dmg *= 1 + 0.31 * b.inventory.length if (powerUps.boost.endCycle > m.cycle) dmg *= 1 + powerUps.boost.damage @@ -2047,9 +2047,9 @@ const tech = { frequency: 1, frequencyDefault: 1, allowed() { - return m.fieldMode !== 9 && !tech.isTokamak + return m.fieldMode !== 9 && !tech.isTokamak && !tech.isReel }, - requires: "not wormhole, tokamak", + requires: "not wormhole, reel, tokamak", effect() { tech.blockDamage = 0.3 }, @@ -5670,7 +5670,7 @@ const tech = { frequency: 2, frequencyDefault: 2, allowed() { - return !tech.isImmuneExplosion && (build.isExperimentSelection || powerUps.research.count > 1) && (tech.haveGunCheck("missiles") || (m.fieldMode === 4 && simulation.molecularMode === 1) || tech.missileBotCount > 0 || tech.isIncendiary || tech.isPulseLaser || tech.isTokamak || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb)) + return !tech.isImmuneExplosion && (build.isExperimentSelection || powerUps.research.count > 1) && (tech.haveGunCheck("missiles") || (m.fieldMode === 4 && simulation.molecularMode === 1) || tech.missileBotCount > 0 || tech.isIncendiary || tech.isPulseLaser || tech.isTokamak || tech.isHookExplosion || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb)) }, requires: "an explosive damage source, not rocket propelled grenade", effect() { @@ -6780,7 +6780,7 @@ const tech = { name: "capacitor bank", // description: "charge effects build up almost instantly
throwing blocks, foam, railgun, pulse, tokamak", descriptionFunction() { - return `charge effects build up almost instantly
throwing, ${tech.haveGunCheck("foam", false) ? "foam" : "foam"}, ${tech.isPlasmaBall ? "plasma ball" : "plasma ball"}, ${tech.isRailGun ? "railgun" : "railgun"}, ${tech.isPulseLaser ? "pulse" : "pulse"}, ${tech.isTokamak ? "tokamak" : "tokamak"}` + return `charge effects build up almost instantly
blocks, ${tech.haveGunCheck("foam", false) ? "foam" : "foam"}, ${tech.isPlasmaBall ? "plasma ball" : "plasma ball"}, ${tech.isRailGun ? "railgun" : "railgun"}, ${tech.isPulseLaser ? "pulse" : "pulse"}, ${tech.isTokamak ? "tokamak" : "tokamak"}` }, isGunTech: true, maxCount: 1, @@ -6917,6 +6917,25 @@ const tech = { tech.isRailEnergy = false; } }, + { + name: "autonomous defense", + description: "if you collide with a mob
fire harpoons at nearby mobs", + isGunTech: true, + maxCount: 1, + count: 0, + frequency: 2, + frequencyDefault: 2, + allowed() { + return tech.haveGunCheck("harpoon") + }, + requires: "harpoon", + effect() { + tech.isHarpoonDefense = true + }, + remove() { + tech.isHarpoonDefense = false + } + }, { name: "Bessemer process", descriptionFunction() { @@ -7718,7 +7737,7 @@ const tech = { }, { name: "neutronium", - description: `move and jump 20% slower
if your field is active +90% defense`, + description: `move and jump 20% slower
if your field is active +95% defense`, isFieldTech: true, maxCount: 1, count: 0, @@ -7746,7 +7765,7 @@ const tech = { }, { name: "aerostat", - description: `+100% damage while off the ground
-25% damage while on the ground`, + description: `+100% damage while off the ground
-15% damage while on the ground`, isFieldTech: true, maxCount: 1, count: 0, @@ -8102,9 +8121,9 @@ const tech = { frequency: 2, frequencyDefault: 2, allowed() { - return (m.fieldMode === 5 || m.fieldMode === 4) && !tech.isPrinter + return (m.fieldMode === 5 || m.fieldMode === 4 || m.fieldMode === 10) && !tech.isPrinter && !tech.isReel }, - requires: "plasma torch, molecular assembler, not printer", + requires: "plasma torch, molecular assembler, grappling hook, not printer, reel", effect() { tech.isTokamak = true; }, @@ -8114,7 +8133,7 @@ const tech = { }, { name: "degenerate matter", - description: "if your field is active
+75% defense", + description: "if your field is active
+85% defense", isFieldTech: true, maxCount: 1, count: 0, @@ -8755,7 +8774,7 @@ const tech = { } }, { - name: "autonomous defense", + name: "CIWS", description: "grappling hook uses 20 energy
to fire harpoons at nearby mobs", isFieldTech: true, maxCount: 1, @@ -8792,8 +8811,29 @@ const tech = { tech.isHookExplosion = false } }, + { + name: "reel", + description: "+400% block collision damage
+30 energy when reeling in far away blocks", + isFieldTech: true, + maxCount: 1, + count: 0, + frequency: 1, + frequencyDefault: 1, + allowed() { + return m.fieldMode === 10 && !tech.isTokamak && tech.blockDamage === 0.075 + }, + requires: "not mass driver", + effect() { + tech.blockDamage = 0.375 + tech.isReel = true + }, + remove() { + tech.blockDamage = 0.075 + tech.isReel = false + } + }, // { - // name: "autonomous defense", + // name: "CIWS", // description: "if you collide with a mob
fire harpoons at nearby mobs", // isFieldTech: true, // maxCount: 1, @@ -11879,4 +11919,6 @@ const tech = { // isHookWire: null, isHookDefense: null, isHookExplosion: null, + isHarpoonDefense: null, + isReel: null, } \ No newline at end of file diff --git a/todo.txt b/todo.txt index bd298b9..024fe8e 100644 --- a/todo.txt +++ b/todo.txt @@ -1,28 +1,34 @@ ******************************************************** NEXT PATCH ************************************************** -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 +new community level shipwreck by 3xionDev -negative mass field has horizontal block motion by default -fixed tech sorting by "allowed tech" in experiment mode +grappling hook + tech: reel - increase block damage 400%, generate 30 energy after hooking blocks + added tokamak to grappling hook + updated rope graphics + added input.up to adjust positioning while hook is attached + added images for CIWS, rupture, autonomous defense + aerostat: 25->15% reduced damage on ground + rupture unlocks explosive tech + rupture destroys blocks + autonomous defense renamed to CIWS + +field emitter 6->4 base energy regen +tech: autonomous defense - harpoon tech that fires harpoons after taking damage +degenerate matter: 75->85% defense while field is active +neutronium: 90->95% defense while field is active +unified field theory no longer has field emitter as an option *********************************************************** TODO ***************************************************** -grappling hook is a field +player got stuck inside block that wasn't pick up able + +grappling hook field check for places that the player could get into but not out of field tech ideas - hook and line stuns? - increase hook damage - hook damage aura - hook's line does damage - generate ___ after destroying blocks + Buoyancy - aerostat, but for defense: +70% defense while off the ground + too similar to degenerate matter + generate ___ after destroying blocks energy, drones, iceIX, explosion, nails, junk bots? tech - killing a mob heals for the last damage you took @@ -30,6 +36,10 @@ tech - killing a mob heals for the last damage you took heal for 50%? heal from mob damage or from kills? +on sucker mob death trigger radiation damage AoE and a graphic (Hawking radiation) + +tech prismatic laser - cycles between different laser colors every 1-2 seconds + make phonon the default wave gun type and make a tech to switch to the normal wave beam nerf phonon, buff wave @@ -1095,6 +1105,7 @@ add sounds ******************************************************** LORE ******************************************************** possible names for tech + sidereal - with respect to the stars (an extra rotation for time keeping) strange loop holonomy - parallel transport of a vector leads to movement (applies to curved space) hypergolic - A hypergolic propellant combination used in a rocket engine is one whose components spontaneously ignite when they come into contact with each other.