From 4e1c5467e34157736b550430af142875fb8ee159 Mon Sep 17 00:00:00 2001 From: landgreen Date: Tue, 14 Apr 2020 19:00:29 -0700 Subject: [PATCH] bug fixes, pulse stun mod --- js/bullets.js | 129 ++++++------ js/level.js | 12 +- js/player.js | 545 +++++++++++++++++++++++++------------------------- js/spawn.js | 18 +- todo.txt | 27 +-- 5 files changed, 378 insertions(+), 353 deletions(-) diff --git a/js/bullets.js b/js/bullets.js index 73ca1b0..7ae9c60 100644 --- a/js/bullets.js +++ b/js/bullets.js @@ -37,7 +37,6 @@ const b = { isModPiezo: null, isModDroneCollide: null, isModFastSpores: null, - isModStomp: null, modSuperBallNumber: null, modOneSuperBall: null, modLaserReflections: null, @@ -79,6 +78,7 @@ const b = { isModSporeFollow: null, isModNailPoison: null, isModEnergyHealth: null, + isModPulseStun: null, modOnHealthChange() { //used with acid mod if (b.isModAcidDmg && mech.health > 0.8) { b.modAcidDmg = 0.5 @@ -144,13 +144,13 @@ const b = { }, { name: "fracture analysis", - description: "5x physical damage to unaware mobs
unaware mobs don't have a health bar", + description: "bullets do 5x damage to unaware mobs
unaware mobs don't have a health bar", maxCount: 1, count: 0, allowed() { - return b.isModFarAwayDmg + return true }, - requires: "kinetic bombardment", + requires: "", effect() { b.isModCrit = true; }, @@ -201,9 +201,9 @@ const b = { maxCount: 1, count: 0, allowed() { - return b.isModLowHealthDmg + return true }, - requires: "negative feedback", + requires: "", effect() { b.isModHarmDamage = true; }, @@ -261,7 +261,7 @@ const b = { }, { name: "mass driver", - description: "blocks do 3x more damage to mobs
charge throws in 3x less time", + description: "blocks do 2x more damage to mobs
charge throws more quickly for less energy", maxCount: 1, count: 0, allowed() { @@ -269,7 +269,7 @@ const b = { }, requires: "", effect() { - b.modThrowChargeRate = 3 + b.modThrowChargeRate = 2 }, remove() { b.modThrowChargeRate = 1 @@ -402,6 +402,22 @@ const b = { b.modMobDieAtHealth = 0.05; } }, + { + name: "scrap recycling", + description: "heal up to 1% of max health every second
active for 5 seconds after a mob dies", + maxCount: 1, + count: 0, + allowed() { + return true + }, + requires: "", + effect() { + b.isModHealthRecovery = true; + }, + remove() { + b.isModHealthRecovery = false; + } + }, { name: "waste energy recovery", description: "regen 7% of max energy every second
active for 5 seconds after a mob dies", @@ -418,31 +434,15 @@ const b = { b.isModEnergyRecovery = false; } }, - { - name: "scrap recycling", - description: "heal up to 1% of max health every second
active for 5 seconds after a mob dies", - maxCount: 1, - count: 0, - allowed() { - return b.isModEnergyRecovery - }, - requires: "waste energy recovery", - effect() { - b.isModHealthRecovery = true; - }, - remove() { - b.isModHealthRecovery = false; - } - }, { name: "acute stress response", description: "increase damage by 33%
but, after a mob dies lose 1/2 your energy", maxCount: 1, count: 0, allowed() { - return b.isModEnergyRecovery + return true }, - requires: "waste energy recovery", + requires: "", effect() { b.isModEnergyLoss = true; }, @@ -470,22 +470,6 @@ const b = { mech.jumpForce = 0.42; //was 0.38 at 0.0019 gravity } }, - { - name: "basidio-stomp", - description: "hard landings disrupt spores in the ground
immune to harm from falling", - maxCount: 1, - count: 0, - allowed() { - return b.modSquirrelFx > 1 - }, - requires: "squirrel-cage rotor", - effect() { - b.isModStomp = true - }, - remove() { - b.isModStomp = false; - } - }, { name: "Pauli exclusion", description: `unable to collide with mobs for +2 seconds
activates after being harmed from a collision`, @@ -525,9 +509,9 @@ const b = { maxCount: 1, count: 0, allowed() { - return b.isModImmortal + return true }, - requires: "quantum immortality", + requires: "", effect() { b.isModDeathAvoid = true; b.isModDeathAvoidOnCD = false; @@ -560,7 +544,7 @@ const b = { }, { name: "mass-energy equivalence", - description: "your energy replaces your health
you can't die if your energy is above zero", + description: "you can't die if your energy is above zero
your health is permanently set to zero", maxCount: 1, count: 0, allowed() { @@ -1175,7 +1159,7 @@ const b = { maxCount: 1, count: 0, allowed() { - return b.haveGunCheck("spores") || b.modSporesOnDeath > 0 || b.isModStomp || b.isModSporeField + return b.haveGunCheck("spores") || b.modSporesOnDeath > 0 || b.isModSporeField }, requires: "spores", effect() { @@ -1191,7 +1175,7 @@ const b = { maxCount: 1, count: 0, allowed() { - return b.haveGunCheck("spores") || b.modSporesOnDeath > 0 || b.isModStomp || b.isModSporeField + return b.haveGunCheck("spores") || b.modSporesOnDeath > 0 || b.isModSporeField }, requires: "spores", effect() { @@ -1301,6 +1285,22 @@ const b = { b.modLaserFieldDrain = 0.002; } }, + { + name: "shock wave", + description: "mobs caught in pulse's explosion are stunned", + maxCount: 1, + count: 0, + allowed() { + return b.haveGunCheck("pulse") + }, + requires: "pulse", + effect() { + b.isModPulseStun = true; + }, + remove() { + b.isModPulseStun = false; + } + }, { name: "flux pinning", description: "blocking with perfect diamagnetism
stuns mobs for +1 second", @@ -1568,14 +1568,21 @@ const b = { game.updateGunHUD(); } } else { - if (b.isModAmmoFromHealth && mech.health > 0.05) { - mech.damage(Math.max(0.01, b.isModAmmoFromHealth * mech.health)); - powerUps.spawn(mech.pos.x, mech.pos.y, "ammo"); - if (Math.random() < b.isModBayesian) powerUps.spawn(mech.pos.x, mech.pos.y, "ammo"); + if (b.isModAmmoFromHealth) { + if (mech.health > 0.05) { + mech.damage(Math.max(0.01, b.isModAmmoFromHealth * mech.health)); + powerUps.spawn(mech.pos.x, mech.pos.y, "ammo"); + if (Math.random() < b.isModBayesian) powerUps.spawn(mech.pos.x, mech.pos.y, "ammo"); + } else { + game.replaceTextLog = true; + game.makeTextLog("not enough health for catabolism to produce ammo", 120); + } + + } else { + game.replaceTextLog = true; + game.makeTextLog("
NO AMMO

Q, E, and mouse wheel change weapons

", 200); } - mech.fireCDcycle = mech.cycle + 30; //fire cooldown - game.replaceTextLog = true; - game.makeTextLog("
NO AMMO

Q, E, and mouse wheel change weapons

", 200); + mech.fireCDcycle = mech.cycle + 30; //fire cooldown } if (mech.holdingTarget) { mech.drop(); @@ -2117,7 +2124,7 @@ const b = { friction: 0, frictionAir: 0.10, restitution: 0.3, - dmg: 0.18, //damage done in addition to the damage from momentum + dmg: 0.17, //damage done in addition to the damage from momentum lookFrequency: 10 + Math.floor(7 * Math.random()), endCycle: game.cycle + 120 * b.isModBulletsLastLonger, //Math.floor((1200 + 420 * Math.random()) * b.isModBulletsLastLonger), classType: "bullet", @@ -3286,7 +3293,7 @@ const b = { if (who.shield) { for (let i = 0, len = mob.length; i < len; i++) { if (mob[i].id === who.shieldTargetID) { //apply some knock back to shield mob before shield breaks - const force = Matter.Vector.mult(this.velocity, 15 / mob[i].mass) + const force = Matter.Vector.mult(this.velocity, 7 / mob[i].mass) Matter.Body.setVelocity(mob[i], { x: mob[i].velocity.x + force.x, y: mob[i].velocity.y + force.y @@ -3757,6 +3764,16 @@ const b = { if (best.who) b.explosion(path[1], 1000 * energy, true) mech.fireCDcycle = mech.cycle + Math.floor(60 * b.modFireRate); // cool down + if (b.isModPulseStun) { + const range = 100 + 2000 * energy + for (let i = 0, len = mob.length; i < len; ++i) { + if (mob[i].alive && !mob[i].isShielded) { + dist = Vector.magnitude(Vector.sub(path[1], mob[i].position)) - mob[i].radius; + if (dist < range) mobs.statusStun(mob[i], 30 + Math.floor(energy * 60)) + } + } + } + //draw laser beam ctx.beginPath(); ctx.moveTo(path[0].x, path[0].y); diff --git a/js/level.js b/js/level.js index 17b2da6..81b4f5b 100644 --- a/js/level.js +++ b/js/level.js @@ -146,9 +146,9 @@ const level = { spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 100); //exit bump // spawn.laserBoss(2900, -500) - // spawn.sucker(1200, -500) + spawn.striker(1200, -500) // spawn.timeSkipBoss(2900, -500) - spawn.randomMob(1600, -500) + // spawn.randomMob(1600, -500) }, bosses() { @@ -492,12 +492,12 @@ const level = { spawn.mapRect(5200, -775, 100, 920); spawn.mapRect(5300, -1075, 350, 1220); spawn.boost(5825, 235, 1400); - level.fillBG.push({ + level.fill.push({ x: 5200, y: 125, width: 450, height: 200, - color: "rgba(0,20,40,0.2)" + color: "rgba(0,20,40,0.25)" }); //structure bellow tall stairs @@ -522,12 +522,12 @@ const level = { spawn.mapRect(4100, -3450, 100, 700); //left top shelf spawn.mapRect(4200, -3450, 100, 400); //left top shelf spawn.mapRect(4300, -3450, 100, 100); //left top shelf - level.fillBG.push({ + level.fill.push({ x: 4100, y: -3450, width: 500, height: 1750, - color: "#d0d4d6" + color: "rgba(0,20,40,0.1)" }); level.fill.push({ x: 4100, diff --git a/js/player.js b/js/player.js index 33ff1a9..6d81d1e 100644 --- a/js/player.js +++ b/js/player.js @@ -886,8 +886,8 @@ const mech = { throwBlock() { if (mech.holdingTarget) { if (keys[32] || game.mouseDownRight) { - if (mech.energy > 0.0007) { - mech.energy -= 0.0007; + if (mech.energy > 0.001) { + mech.energy -= 0.001 / b.modThrowChargeRate; mech.throwCharge += 0.5 * b.modThrowChargeRate / mech.holdingTarget.mass //draw charge const x = mech.pos.x + 15 * Math.cos(mech.angle); @@ -1261,6 +1261,46 @@ const mech = { } } }, + { + name: "standing wave harmonics", + description: "three oscillating shields are permanently active
energy regenerates while field is active", + isEasyToAim: true, + effect: () => { + mech.hold = function () { + if (mech.isHolding) { + mech.drawHold(mech.holdingTarget); + mech.holding(); + mech.throwBlock(); + } else if ((keys[32] || game.mouseDownRight) && mech.fieldCDcycle < mech.cycle) { //not hold but field button is pressed + mech.grabPowerUp(); + mech.lookForPickUp(); + } else if (mech.holdingTarget && mech.fieldCDcycle < mech.cycle) { //holding, but field button is released + mech.pickUp(); + } else { + mech.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 (mech.energy > 0.1 && mech.fieldCDcycle < mech.cycle) { + const fieldRange1 = (0.55 + 0.35 * Math.sin(mech.cycle / 23)) * mech.fieldRange + const fieldRange2 = (0.5 + 0.4 * Math.sin(mech.cycle / 37)) * mech.fieldRange + const fieldRange3 = (0.45 + 0.45 * Math.sin(mech.cycle / 47)) * mech.fieldRange + const netfieldRange = Math.max(fieldRange1, fieldRange2, fieldRange3) + ctx.fillStyle = "rgba(110,170,200," + (0.04 + mech.energy * (0.12 + 0.13 * Math.random())) + ")"; + ctx.beginPath(); + ctx.arc(mech.pos.x, mech.pos.y, fieldRange1, 0, 2 * Math.PI); + ctx.fill(); + ctx.beginPath(); + ctx.arc(mech.pos.x, mech.pos.y, fieldRange2, 0, 2 * Math.PI); + ctx.fill(); + ctx.beginPath(); + ctx.arc(mech.pos.x, mech.pos.y, fieldRange3, 0, 2 * Math.PI); + ctx.fill(); + mech.pushMobs360(netfieldRange); + // mech.pushBody360(netfieldRange); //can't throw block when pushhing blocks away + } + mech.drawFieldMeter() + } + } + }, { name: "perfect diamagnetism", // description: "gain energy when blocking
no recoil when blocking", @@ -1320,97 +1360,192 @@ const mech = { } }, { - name: "time dilation field", - description: "use energy to stop time
you can move and fire while time is stopped", + name: "nano-scale manufacturing", + description: "excess energy used to build drones
2x energy regeneration", isEasyToAim: true, effect: () => { - // mech.fieldMeterColor = "#000" - mech.fieldFire = true; - mech.isBodiesAsleep = false; + // mech.fieldRegen *= 2; mech.hold = function () { + if (mech.energy > mech.fieldEnergyMax - 0.02 && mech.fieldCDcycle < mech.cycle) { + if (b.isModSporeField) { + // mech.fieldCDcycle = mech.cycle + 10; // set cool down to prevent +energy from making huge numbers of drones + const len = Math.floor(6 + 4 * Math.random()) + mech.energy -= len * 0.074; + for (let i = 0; i < len; i++) { + b.spore(player) + } + } else if (b.isModMissileField) { + // mech.fieldCDcycle = mech.cycle + 10; // set cool down to prevent +energy from making huge numbers of drones + mech.energy -= 0.5; + b.missile({ + x: mech.pos.x + 40 * Math.cos(mech.angle), + y: mech.pos.y + 40 * Math.sin(mech.angle) - 3 + }, + mech.angle + (0.5 - Math.random()) * (mech.crouch ? 0 : 0.2), + -3 * (0.5 - Math.random()) + (mech.crouch ? 25 : -8) * b.modFireRate, + 1, b.modBabyMissiles) + } else if (b.isModIceField) { + // mech.fieldCDcycle = mech.cycle + 17; // set cool down to prevent +energy from making huge numbers of drones + mech.energy -= 0.061; + b.iceIX(1) + } else { + // mech.fieldCDcycle = mech.cycle + 10; // set cool down to prevent +energy from making huge numbers of drones + mech.energy -= 0.33; + b.drone(1) + } + + } if (mech.isHolding) { - mech.wakeCheck(); mech.drawHold(mech.holdingTarget); mech.holding(); mech.throwBlock(); - } else if ((keys[32] || game.mouseDownRight) && mech.fieldCDcycle < mech.cycle) { + } else if ((keys[32] || game.mouseDownRight && mech.fieldCDcycle < mech.cycle)) { //not hold but field button is pressed mech.grabPowerUp(); - mech.lookForPickUp(180); - - const DRAIN = 0.0017 - if (mech.energy > DRAIN) { - mech.energy -= DRAIN; - if (mech.energy < DRAIN) { - mech.fieldCDcycle = mech.cycle + 120; - mech.energy = 0; - mech.wakeCheck(); - } - //draw field everywhere - ctx.globalCompositeOperation = "saturation" - // ctx.fillStyle = "rgba(100,200,230," + (0.25 + 0.06 * Math.random()) + ")"; - ctx.fillStyle = "#ccc"; - ctx.fillRect(-100000, -100000, 200000, 200000) - ctx.globalCompositeOperation = "source-over" - //stop time - mech.isBodiesAsleep = true; - - function sleep(who) { - for (let i = 0, len = who.length; i < len; ++i) { - if (!who[i].isSleeping) { - who[i].storeVelocity = who[i].velocity - who[i].storeAngularVelocity = who[i].angularVelocity - } - Matter.Sleeping.set(who[i], true) - } - } - sleep(mob); - sleep(body); - sleep(bullet); - //doesn't really work, just slows down constraints - for (let i = 0, len = cons.length; i < len; i++) { - if (cons[i].stiffness !== 0) { - cons[i].storeStiffness = cons[i].stiffness; - cons[i].stiffness = 0; - } - } - - game.cycle--; //pause all functions that depend on game cycle increasing - if (b.isModTimeSkip) { - game.isTimeSkipping = true; - mech.cycle++; - game.gravity(); - Engine.update(engine, game.delta); - // level.checkZones(); - // level.checkQuery(); - mech.move(); - game.checks(); - // mobs.loop(); - // mech.draw(); - mech.walk_cycle += mech.flipLegs * mech.Vx; - // mech.hold(); - mech.energy += 0.5 * DRAIN; //x1 to undo the energy drain from time speed up, x1.5 to cut energy drain in half - b.fire(); - // b.bulletRemove(); - b.bulletDo(); - game.isTimeSkipping = false; - } - // game.cycle--; //pause all functions that depend on game cycle increasing - // if (b.isModTimeSkip && !game.isTimeSkipping) { //speed up the rate of time - // game.timeSkip(1) - // mech.energy += 1.5 * DRAIN; //x1 to undo the energy drain from time speed up, x1.5 to cut energy drain in half - // } + mech.lookForPickUp(); + if (mech.energy > 0.05) { + mech.drawField(); + mech.pushMobsFacing(); } } else if (mech.holdingTarget && mech.fieldCDcycle < mech.cycle) { //holding, but field button is released - mech.wakeCheck(); mech.pickUp(); } else { - mech.wakeCheck(); mech.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists) } + mech.energy += mech.fieldRegen; mech.drawFieldMeter() } } }, + { + name: "negative mass field", + description: "use energy to nullify   gravity
reduce harm by 80% while field is active", //
launch larger blocks at much higher speeds + fieldDrawRadius: 0, + isEasyToAim: true, + effect: () => { + mech.fieldFire = true; + mech.holdingMassScale = 0.03; //can hold heavier blocks with lower cost to jumping + mech.fieldMeterColor = "#000" + + mech.hold = function () { + mech.fieldDamageResistance = 1; + if (mech.isHolding) { + mech.drawHold(mech.holdingTarget); + mech.holding(); + mech.throwBlock(); + } else if ((keys[32] || game.mouseDownRight) && mech.fieldCDcycle < mech.cycle) { //push away + mech.grabPowerUp(); + mech.lookForPickUp(); + const DRAIN = 0.00035 + if (mech.energy > DRAIN) { + mech.fieldDamageResistance = 0.2; // 1 - 0.8 + // mech.pushMobs360(); + + //repulse mobs + // for (let i = 0, len = mob.length; i < len; ++i) { + // sub = Vector.sub(mob[i].position, mech.pos); + // dist2 = Vector.magnitudeSquared(sub); + // if (dist2 < this.fieldDrawRadius * this.fieldDrawRadius && mob[i].speed > 6) { + // const force = Vector.mult(Vector.perp(Vector.normalise(sub)), 0.00004 * mob[i].speed * mob[i].mass) + // mob[i].force.x = force.x + // mob[i].force.y = force.y + // } + // } + + + //look for nearby objects to make zero-g + function zeroG(who, range, mag = 1.06) { + for (let i = 0, len = who.length; i < len; ++i) { + sub = Vector.sub(who[i].position, mech.pos); + dist = Vector.magnitude(sub); + if (dist < range) { + who[i].force.y -= who[i].mass * (game.g * mag); //add a bit more then standard gravity + } + } + } + // zeroG(bullet); //works fine, but not that noticeable and maybe not worth the possible performance hit + // zeroG(mob); //mobs are too irregular to make this work? + + if (keys[83] || keys[40]) { //down + player.force.y -= 0.5 * player.mass * mech.gravity; + this.fieldDrawRadius = this.fieldDrawRadius * 0.97 + 400 * 0.03; + zeroG(powerUp, this.fieldDrawRadius, 0.7); + zeroG(body, this.fieldDrawRadius, 0.7); + } else if (keys[87] || keys[38]) { //up + mech.energy -= 5 * DRAIN; + this.fieldDrawRadius = this.fieldDrawRadius * 0.97 + 850 * 0.03; + player.force.y -= 1.45 * player.mass * mech.gravity; + zeroG(powerUp, this.fieldDrawRadius, 1.38); + zeroG(body, this.fieldDrawRadius, 1.38); + } else { + mech.energy -= DRAIN; + this.fieldDrawRadius = this.fieldDrawRadius * 0.97 + 650 * 0.03; + player.force.y -= 1.07 * player.mass * mech.gravity; // slow upward drift + zeroG(powerUp, this.fieldDrawRadius); + zeroG(body, this.fieldDrawRadius); + } + if (mech.energy < 0.001) { + mech.fieldCDcycle = mech.cycle + 120; + mech.energy = 0; + } + //add extra friction for horizontal motion + if (keys[65] || keys[68] || keys[37] || keys[39]) { + Matter.Body.setVelocity(player, { + x: player.velocity.x * 0.99, + y: player.velocity.y * 0.97 + }); + } else { //slow rise and fall + Matter.Body.setVelocity(player, { + x: player.velocity.x, + y: player.velocity.y * 0.97 + }); + } + + //draw zero-G range + ctx.beginPath(); + ctx.arc(mech.pos.x, mech.pos.y, this.fieldDrawRadius, 0, 2 * Math.PI); + ctx.fillStyle = "#f5f5ff"; + ctx.globalCompositeOperation = "difference"; + ctx.fill(); + if (b.isModHawking) { + for (let i = 0, len = mob.length; i < len; i++) { + if (mob[i].distanceToPlayer2() < this.fieldDrawRadius * this.fieldDrawRadius && Matter.Query.ray(map, mech.pos, mob[i].position).length === 0 && Matter.Query.ray(body, mech.pos, mob[i].position).length === 0) { + mob[i].damage(b.dmgScale * 0.085); + mob[i].locatePlayer(); + + //draw electricity + const sub = Vector.sub(mob[i].position, mech.pos) + const unit = Vector.normalise(sub); + const steps = 6 + const step = Vector.magnitude(sub) / steps; + ctx.beginPath(); + let x = mech.pos.x + 30 * unit.x; + let y = mech.pos.y + 30 * unit.y; + ctx.moveTo(x, y); + for (let i = 0; i < steps; i++) { + x += step * (unit.x + 0.7 * (Math.random() - 0.5)) + y += step * (unit.y + 0.7 * (Math.random() - 0.5)) + ctx.lineTo(x, y); + } + ctx.lineWidth = 1; + ctx.strokeStyle = "rgba(0,255,0,0.5)" //"#fff"; + ctx.stroke(); + + } + } + } + ctx.globalCompositeOperation = "source-over"; + } + } else if (mech.holdingTarget && mech.fieldCDcycle < mech.cycle) { //holding, but field button is released + mech.pickUp(); + this.fieldDrawRadius = 0 + } else { + mech.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists) + this.fieldDrawRadius = 0 + } + mech.drawFieldMeter("rgba(0,0,0,0.2)") + } + } + }, { name: "plasma torch", description: "use energy to emit damaging plasma
effective at close range", @@ -1578,228 +1713,93 @@ const mech = { } }, { - name: "negative mass field", - description: "use energy to nullify   gravity
reduce harm by 80% while field is active", //
launch larger blocks at much higher speeds - fieldDrawRadius: 0, + name: "time dilation field", + description: "use energy to stop time
you can move and fire while time is stopped", isEasyToAim: true, effect: () => { + // mech.fieldMeterColor = "#000" mech.fieldFire = true; - mech.holdingMassScale = 0.03; //can hold heavier blocks with lower cost to jumping - mech.fieldMeterColor = "#000" - + mech.isBodiesAsleep = false; mech.hold = function () { - mech.fieldDamageResistance = 1; if (mech.isHolding) { + mech.wakeCheck(); mech.drawHold(mech.holdingTarget); mech.holding(); mech.throwBlock(); - } else if ((keys[32] || game.mouseDownRight) && mech.fieldCDcycle < mech.cycle) { //push away + } else if ((keys[32] || game.mouseDownRight) && mech.fieldCDcycle < mech.cycle) { mech.grabPowerUp(); - mech.lookForPickUp(); - const DRAIN = 0.00035 + mech.lookForPickUp(180); + + const DRAIN = 0.0017 if (mech.energy > DRAIN) { - mech.fieldDamageResistance = 0.2; // 1 - 0.8 - // mech.pushMobs360(); - - //repulse mobs - // for (let i = 0, len = mob.length; i < len; ++i) { - // sub = Vector.sub(mob[i].position, mech.pos); - // dist2 = Vector.magnitudeSquared(sub); - // if (dist2 < this.fieldDrawRadius * this.fieldDrawRadius && mob[i].speed > 6) { - // const force = Vector.mult(Vector.perp(Vector.normalise(sub)), 0.00004 * mob[i].speed * mob[i].mass) - // mob[i].force.x = force.x - // mob[i].force.y = force.y - // } - // } - - - //look for nearby objects to make zero-g - function zeroG(who, range, mag = 1.06) { - for (let i = 0, len = who.length; i < len; ++i) { - sub = Vector.sub(who[i].position, mech.pos); - dist = Vector.magnitude(sub); - if (dist < range) { - who[i].force.y -= who[i].mass * (game.g * mag); //add a bit more then standard gravity - } - } - } - // zeroG(bullet); //works fine, but not that noticeable and maybe not worth the possible performance hit - // zeroG(mob); //mobs are too irregular to make this work? - - if (keys[83] || keys[40]) { //down - player.force.y -= 0.5 * player.mass * mech.gravity; - this.fieldDrawRadius = this.fieldDrawRadius * 0.97 + 400 * 0.03; - zeroG(powerUp, this.fieldDrawRadius, 0.7); - zeroG(body, this.fieldDrawRadius, 0.7); - } else if (keys[87] || keys[38]) { //up - mech.energy -= 5 * DRAIN; - this.fieldDrawRadius = this.fieldDrawRadius * 0.97 + 850 * 0.03; - player.force.y -= 1.45 * player.mass * mech.gravity; - zeroG(powerUp, this.fieldDrawRadius, 1.38); - zeroG(body, this.fieldDrawRadius, 1.38); - } else { - mech.energy -= DRAIN; - this.fieldDrawRadius = this.fieldDrawRadius * 0.97 + 650 * 0.03; - player.force.y -= 1.07 * player.mass * mech.gravity; // slow upward drift - zeroG(powerUp, this.fieldDrawRadius); - zeroG(body, this.fieldDrawRadius); - } - if (mech.energy < 0.001) { + mech.energy -= DRAIN; + if (mech.energy < DRAIN) { mech.fieldCDcycle = mech.cycle + 120; mech.energy = 0; + mech.wakeCheck(); } - //add extra friction for horizontal motion - if (keys[65] || keys[68] || keys[37] || keys[39]) { - Matter.Body.setVelocity(player, { - x: player.velocity.x * 0.99, - y: player.velocity.y * 0.97 - }); - } else { //slow rise and fall - Matter.Body.setVelocity(player, { - x: player.velocity.x, - y: player.velocity.y * 0.97 - }); - } - - //draw zero-G range - ctx.beginPath(); - ctx.arc(mech.pos.x, mech.pos.y, this.fieldDrawRadius, 0, 2 * Math.PI); - ctx.fillStyle = "#f5f5ff"; - ctx.globalCompositeOperation = "difference"; - ctx.fill(); - if (b.isModHawking) { - for (let i = 0, len = mob.length; i < len; i++) { - if (mob[i].distanceToPlayer2() < this.fieldDrawRadius * this.fieldDrawRadius && Matter.Query.ray(map, mech.pos, mob[i].position).length === 0 && Matter.Query.ray(body, mech.pos, mob[i].position).length === 0) { - mob[i].damage(b.dmgScale * 0.085); - mob[i].locatePlayer(); - - //draw electricity - const sub = Vector.sub(mob[i].position, mech.pos) - const unit = Vector.normalise(sub); - const steps = 6 - const step = Vector.magnitude(sub) / steps; - ctx.beginPath(); - let x = mech.pos.x + 30 * unit.x; - let y = mech.pos.y + 30 * unit.y; - ctx.moveTo(x, y); - for (let i = 0; i < steps; i++) { - x += step * (unit.x + 0.7 * (Math.random() - 0.5)) - y += step * (unit.y + 0.7 * (Math.random() - 0.5)) - ctx.lineTo(x, y); - } - ctx.lineWidth = 1; - ctx.strokeStyle = "rgba(0,255,0,0.5)" //"#fff"; - ctx.stroke(); + //draw field everywhere + ctx.globalCompositeOperation = "saturation" + // ctx.fillStyle = "rgba(100,200,230," + (0.25 + 0.06 * Math.random()) + ")"; + ctx.fillStyle = "#ccc"; + ctx.fillRect(-100000, -100000, 200000, 200000) + ctx.globalCompositeOperation = "source-over" + //stop time + mech.isBodiesAsleep = true; + function sleep(who) { + for (let i = 0, len = who.length; i < len; ++i) { + if (!who[i].isSleeping) { + who[i].storeVelocity = who[i].velocity + who[i].storeAngularVelocity = who[i].angularVelocity } + Matter.Sleeping.set(who[i], true) } } - ctx.globalCompositeOperation = "source-over"; - } - } else if (mech.holdingTarget && mech.fieldCDcycle < mech.cycle) { //holding, but field button is released - mech.pickUp(); - this.fieldDrawRadius = 0 - } else { - mech.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists) - this.fieldDrawRadius = 0 - } - mech.drawFieldMeter("rgba(0,0,0,0.2)") - } - } - }, - { - name: "standing wave harmonics", - description: "three oscillating shields are permanently active
energy regenerates while field is active", - isEasyToAim: true, - effect: () => { - mech.hold = function () { - if (mech.isHolding) { - mech.drawHold(mech.holdingTarget); - mech.holding(); - mech.throwBlock(); - } else if ((keys[32] || game.mouseDownRight) && mech.fieldCDcycle < mech.cycle) { //not hold but field button is pressed - mech.grabPowerUp(); - mech.lookForPickUp(); - } else if (mech.holdingTarget && mech.fieldCDcycle < mech.cycle) { //holding, but field button is released - mech.pickUp(); - } else { - mech.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 (mech.energy > 0.1 && mech.fieldCDcycle < mech.cycle) { - const fieldRange1 = (0.55 + 0.35 * Math.sin(mech.cycle / 23)) * mech.fieldRange - const fieldRange2 = (0.5 + 0.4 * Math.sin(mech.cycle / 37)) * mech.fieldRange - const fieldRange3 = (0.45 + 0.45 * Math.sin(mech.cycle / 47)) * mech.fieldRange - const netfieldRange = Math.max(fieldRange1, fieldRange2, fieldRange3) - ctx.fillStyle = "rgba(110,170,200," + (0.04 + mech.energy * (0.12 + 0.13 * Math.random())) + ")"; - ctx.beginPath(); - ctx.arc(mech.pos.x, mech.pos.y, fieldRange1, 0, 2 * Math.PI); - ctx.fill(); - ctx.beginPath(); - ctx.arc(mech.pos.x, mech.pos.y, fieldRange2, 0, 2 * Math.PI); - ctx.fill(); - ctx.beginPath(); - ctx.arc(mech.pos.x, mech.pos.y, fieldRange3, 0, 2 * Math.PI); - ctx.fill(); - mech.pushMobs360(netfieldRange); - // mech.pushBody360(netfieldRange); //can't throw block when pushhing blocks away - } - mech.drawFieldMeter() - } - } - }, - { - name: "nano-scale manufacturing", - description: "excess energy used to build drones
2x energy regeneration", - isEasyToAim: true, - effect: () => { - // mech.fieldRegen *= 2; - mech.hold = function () { - if (mech.energy > mech.fieldEnergyMax - 0.02 && mech.fieldCDcycle < mech.cycle) { - if (b.isModSporeField) { - // mech.fieldCDcycle = mech.cycle + 10; // set cool down to prevent +energy from making huge numbers of drones - const len = Math.floor(6 + 4 * Math.random()) - mech.energy -= len * 0.074; - for (let i = 0; i < len; i++) { - b.spore(player) + sleep(mob); + sleep(body); + sleep(bullet); + //doesn't really work, just slows down constraints + for (let i = 0, len = cons.length; i < len; i++) { + if (cons[i].stiffness !== 0) { + cons[i].storeStiffness = cons[i].stiffness; + cons[i].stiffness = 0; + } } - } else if (b.isModMissileField) { - // mech.fieldCDcycle = mech.cycle + 10; // set cool down to prevent +energy from making huge numbers of drones - mech.energy -= 0.5; - b.missile({ - x: mech.pos.x + 40 * Math.cos(mech.angle), - y: mech.pos.y + 40 * Math.sin(mech.angle) - 3 - }, - mech.angle + (0.5 - Math.random()) * (mech.crouch ? 0 : 0.2), - -3 * (0.5 - Math.random()) + (mech.crouch ? 25 : -8) * b.modFireRate, - 1, b.modBabyMissiles) - } else if (b.isModIceField) { - // mech.fieldCDcycle = mech.cycle + 17; // set cool down to prevent +energy from making huge numbers of drones - mech.energy -= 0.061; - b.iceIX(1) - } else { - // mech.fieldCDcycle = mech.cycle + 10; // set cool down to prevent +energy from making huge numbers of drones - mech.energy -= 0.33; - b.drone(1) - } - } - if (mech.isHolding) { - mech.drawHold(mech.holdingTarget); - mech.holding(); - mech.throwBlock(); - } else if ((keys[32] || game.mouseDownRight && mech.fieldCDcycle < mech.cycle)) { //not hold but field button is pressed - mech.grabPowerUp(); - mech.lookForPickUp(); - if (mech.energy > 0.05) { - mech.drawField(); - mech.pushMobsFacing(); + game.cycle--; //pause all functions that depend on game cycle increasing + if (b.isModTimeSkip) { + game.isTimeSkipping = true; + mech.cycle++; + game.gravity(); + Engine.update(engine, game.delta); + // level.checkZones(); + // level.checkQuery(); + mech.move(); + game.checks(); + // mobs.loop(); + // mech.draw(); + mech.walk_cycle += mech.flipLegs * mech.Vx; + // mech.hold(); + mech.energy += 0.5 * DRAIN; //x1 to undo the energy drain from time speed up, x1.5 to cut energy drain in half + b.fire(); + // b.bulletRemove(); + b.bulletDo(); + game.isTimeSkipping = false; + } + // game.cycle--; //pause all functions that depend on game cycle increasing + // if (b.isModTimeSkip && !game.isTimeSkipping) { //speed up the rate of time + // game.timeSkip(1) + // mech.energy += 1.5 * DRAIN; //x1 to undo the energy drain from time speed up, x1.5 to cut energy drain in half + // } } } else if (mech.holdingTarget && mech.fieldCDcycle < mech.cycle) { //holding, but field button is released + mech.wakeCheck(); mech.pickUp(); } else { + mech.wakeCheck(); mech.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists) } - mech.energy += mech.fieldRegen; mech.drawFieldMeter() } } @@ -2009,6 +2009,7 @@ const mech = { if (mech.energy > DRAIN) { mech.energy -= DRAIN; Matter.Body.setVelocity(body[i], velocity); //give block mouse velocity + Matter.Body.setAngularVelocity(body[i], body[i].angularVelocity * 0.8) body[i].force.y -= body[i].mass * game.g; //remove gravity effects } else { mech.fieldOn = false diff --git a/js/spawn.js b/js/spawn.js index f36e92c..7fc169e 100644 --- a/js/spawn.js +++ b/js/spawn.js @@ -942,7 +942,8 @@ const spawn = { me.g = 0.0002; //required if using 'gravity' me.frictionStatic = 0; me.friction = 0; - me.delay = 100; + me.delay = 120 * game.CDScale; + me.cd = Infinity; Matter.Body.rotate(me, Math.PI * 0.1); spawn.shield(me, x, y); me.onDamage = function () { @@ -950,7 +951,20 @@ const spawn = { }; me.do = function () { this.gravity(); - this.seePlayerCheck(); + if (!(game.cycle % this.seePlayerFreq)) { // this.seePlayerCheck(); from mobs + if ( + this.distanceToPlayer2() < this.seeAtDistance2 && + Matter.Query.ray(map, this.position, this.mechPosRange()).length === 0 && + Matter.Query.ray(body, this.position, this.mechPosRange()).length === 0 && + !mech.isStealth + ) { + this.foundPlayer(); + if (this.cd === Infinity) this.cd = game.cycle + this.delay; + } else if (this.seePlayer.recall) { + this.lostPlayer(); + this.cd = Infinity + } + } this.checkStatus(); this.attraction(); this.strike(); diff --git a/todo.txt b/todo.txt index ad610db..192bcad 100644 --- a/todo.txt +++ b/todo.txt @@ -3,26 +3,19 @@ ************** TODO - n-gon ************** +an effect when canceling a power up + ammo? heals? + 50% chance for a mod, 25% heal, 25% ammo + +liquid nitrogen cooling + Mobs freeze on contact with the player + +uranium reactor core + Mobs get irradiated on contact with the player + add player Scent Trails for mod navigation https://abitawake.com/news/articles/enemy-ai-chasing-a-player-without-navigation2d-or-a-star-pathfinding -mod - energy replaces your health, - -field - pilot wave - while mouse is down blocks (and mobs?) are move with the mouse - players can do serious damage by flicking the mouse and firing blocks - on mouse down calculate relative position of block to mouse and maintain that as mouse moves - on mouse up give blocks the computed mouse velocity - use a gravity effect that pulls blocks in range towards the center of the mouse - maybe no force in the very center to prevent clumping - draw a ellipse around the mouse that wobbles like phase decoherence field, and changes color maybe like negative mass field - -make flurooantimonic acid mod a damage over time - rename to radiation damage? - -mod - radiation damage over time effects can spread to nearby mobs - do a check for nearby mobs on each tick - try adding a subtile shift of color towards red, green or blue block, map, background, text? color could be random as each level loads