From 0ff8021ea853f1425024152e9a7e14e971292a04 Mon Sep 17 00:00:00 2001 From: landgreen Date: Sat, 16 May 2020 09:46:43 -0700 Subject: [PATCH] drone rework, reroll mods anthropic principle - now consumes 1 rerolls, and heals player to 50% health instead of letting them die many worlds - 66% chance for rerolls quantum immortality - also gives 3 rerolls mod drones - Brushless Motor: drones move faster mod drones - redundant systems: removed choices in power up selection should no longer repeat the previous choices when possible --- js/bullets.js | 136 ++++++++++++++++++++++++++----------------------- js/engine.js | 30 ++--------- js/level.js | 8 +-- js/mobs.js | 18 ++++--- js/player.js | 57 ++++++++------------- js/powerups.js | 112 +++++++++++++++++++++++++++++++--------- js/spawn.js | 6 +-- todo.txt | 20 +++++--- 8 files changed, 215 insertions(+), 172 deletions(-) diff --git a/js/bullets.js b/js/bullets.js index c1441db..1ec48a0 100644 --- a/js/bullets.js +++ b/js/bullets.js @@ -36,7 +36,7 @@ const b = { modCollisionImmuneCycles: null, modBlockDmg: null, isModPiezo: null, - isModDroneCollide: null, + isModFastDrones: null, isModFastSpores: null, modSuperBallNumber: null, modOneSuperBall: null, @@ -49,7 +49,6 @@ const b = { isModHealthRecovery: null, isModEnergyLoss: null, isModDeathAvoid: null, - isModDeathAvoidOnCD: null, modWaveSpeedMap: null, modWaveSpeedBody: null, isModSporeField: null, @@ -531,7 +530,7 @@ const b = { }, { name: "Pauli exclusion", - description: `unable to collide with mobs for +2 seconds
activates after being harmed from a collision`, + description: `immune to harm for +1 seconds
activates after being harmed from a collision`, maxCount: 9, count: 0, allowed() { @@ -539,8 +538,8 @@ const b = { }, requires: "", effect() { - b.modCollisionImmuneCycles += 120; - mech.collisionImmuneCycle = mech.cycle + b.modCollisionImmuneCycles; //player is immune to collision damage for 30 cycles + b.modCollisionImmuneCycles += 60; + mech.immuneCycle = mech.cycle + b.modCollisionImmuneCycles; //player is immune to collision damage for 30 cycles }, remove() { b.modCollisionImmuneCycles = 30; @@ -562,40 +561,6 @@ const b = { b.isModSlowFPS = false; } }, - { - name: "quantum immortality", - description: "after dying, continue in an alternate reality
guns, ammo, field, and mods are randomized", - maxCount: 1, - count: 0, - allowed() { - return true - }, - requires: "", - effect() { - b.isModImmortal = true; - }, - remove() { - b.isModImmortal = false; - } - }, - { - name: "anthropic principle", - description: "fatal harm can't happen
saves you up to once every 3 seconds", - maxCount: 1, - count: 0, - allowed() { - return true - }, - requires: "", - effect() { - b.isModDeathAvoid = true; - b.isModDeathAvoidOnCD = false; - }, - remove() { - b.isModDeathAvoid = false; - b.isModDeathAvoidOnCD = false; - } - }, { name: "entanglement", nameInfo: "", @@ -780,7 +745,7 @@ const b = { }, { name: "Bayesian inference", - description: "33% chance for double power ups to drop
remove all future ammo power ups", + description: "37% chance for double power ups to drop
remove all future ammo power ups", maxCount: 1, count: 0, allowed() { @@ -788,7 +753,7 @@ const b = { }, requires: "", effect: () => { - b.modBayesian = 0.33; + b.modBayesian = 0.37; }, remove() { b.modBayesian = 0; @@ -828,7 +793,7 @@ const b = { }, { name: "determinism", - description: "spawn 4 mods and 2 heal power ups
future power ups are limited to one choice", + description: "spawn 5 mods and 2 heal power ups
future power ups are limited to one choice", maxCount: 1, count: 0, allowed() { @@ -837,7 +802,7 @@ const b = { requires: "not cardinality", effect: () => { b.isModDeterminism = true; - for (let i = 0; i < 4; i++) { //if you change the six also change it in Born rule + for (let i = 0; i < 5; i++) { //if you change the six also change it in Born rule powerUps.spawn(mech.pos.x, mech.pos.y, "mod"); if (Math.random() < b.modBayesian) powerUps.spawn(mech.pos.x, mech.pos.y, "mod"); } @@ -852,7 +817,7 @@ const b = { }, { name: "many worlds", - description: "spawn a reroll after choosing a power up", + description: "after choosing a gun, field, or mod
66% chance to spawn a reroll", maxCount: 1, count: 0, allowed() { @@ -870,6 +835,45 @@ const b = { b.manyWorlds = false; } }, + { + name: "anthropic principle", + nameInfo: "", + description: "heal to 50% health instead of dying
consumes 1 reroll", + maxCount: 1, + count: 0, + allowed() { + return powerUps.reroll.rerolls > 0 || build.isCustomSelection + }, + requires: "at least 1 reroll", + effect() { + b.isModDeathAvoid = true; + setTimeout(function () { + powerUps.reroll.changeRerolls(0) + }, 1000); + }, + remove() { + b.isModDeathAvoid = false; + } + }, + { + name: "quantum immortality", + description: "after dying, continue in an alternate reality
spawn 3 rerolls", + maxCount: 1, + count: 0, + allowed() { + return true + }, + requires: "", + effect() { + b.isModImmortal = true; + powerUps.spawn(mech.pos.x, mech.pos.y, "reroll", false); + powerUps.spawn(mech.pos.x, mech.pos.y, "reroll", false); + powerUps.spawn(mech.pos.x, mech.pos.y, "reroll", false); + }, + remove() { + b.isModImmortal = false; + } + }, { name: "Born rule", description: "remove all current mods
spawn new mods to replace them", @@ -991,7 +995,7 @@ const b = { }, { name: "shotgun spin-statistics", - description: "firing the shotgun makes you
immune to collisions for 1 second", + description: "firing the shotgun makes you
immune to harm for 1 second", maxCount: 1, count: 0, allowed() { @@ -1364,8 +1368,8 @@ const b = { } }, { - name: "redundant systems", - description: "drone collisions no longer reduce their lifespan", + name: "brushless motor", + description: "drones accelerate 50% faster", maxCount: 1, count: 0, allowed() { @@ -1373,10 +1377,10 @@ const b = { }, requires: "drones", effect() { - b.isModDroneCollide = true + b.isModFastDrones = true }, remove() { - b.isModDroneCollide = true; + b.isModFastDrones = false } }, { @@ -2133,7 +2137,7 @@ const b = { let collide = Matter.Query.collides(this, map) //check if collides with map if (collide.length > 0) { for (let i = 0; i < collide.length; i++) { - if (collide[i].bodyA.collisionFilter.category === cat.map || collide[i].bodyB.collisionFilter.category === cat.map) { + if (collide[i].bodyA.collisionFilter.category === cat.map) { // || collide[i].bodyB.collisionFilter.category === cat.map) { const angle = Matter.Vector.angle(collide[i].normal, { x: 1, y: 0 @@ -2141,7 +2145,7 @@ const b = { Matter.Body.setAngle(this, Math.atan2(collide[i].tangent.y, collide[i].tangent.x)) //move until touching map again after rotation for (let j = 0; j < 10; j++) { - if (Matter.Query.collides(this, map).length > 0) { + if (Matter.Query.collides(this, map).length > 0) { //touching map if (angle > -0.2 || angle < -1.5) { //don't stick to level ground Matter.Body.setStatic(this, true) //don't set to static if not touching map } else { @@ -2156,7 +2160,8 @@ const b = { //sometimes the mine can't attach to map and it just needs to be reset const that = this setTimeout(function () { - if (Matter.Query.collides(that, map).length === 0) { + if (Matter.Query.collides(that, map).length === 0 || Matter.Query.point(map, that.position).length > 0) { + console.log(that) that.endCycle = 0 // if not touching map explode that.isArmed = false b.mine(that.position, that.velocity, that.angle) @@ -2366,17 +2371,18 @@ const b = { }, drone(speed = 1) { const me = bullet.length; - const THRUST = 0.0015 - const dir = mech.angle + 0.2 * (Math.random() - 0.5); + const THRUST = b.isModFastDrones ? 0.0025 : 0.0015 + const FRICTION = b.isModFastDrones ? 0.008 : 0.0005 + const dir = mech.angle + 0.4 * (Math.random() - 0.5); const RADIUS = (4.5 + 3 * Math.random()) bullet[me] = Bodies.polygon(mech.pos.x + 30 * Math.cos(mech.angle), mech.pos.y + 30 * Math.sin(mech.angle), 8, RADIUS, { angle: dir, inertia: Infinity, friction: 0.05, - frictionAir: 0.0005, + frictionAir: FRICTION, restitution: 1, dmg: 0.23, //damage done in addition to the damage from momentum - lookFrequency: 107 + Math.floor(47 * Math.random()), + lookFrequency: 100 + Math.floor(23 * Math.random()), endCycle: game.cycle + Math.floor((1200 + 420 * Math.random()) * b.isModBulletsLastLonger), classType: "bullet", collisionFilter: { @@ -2396,7 +2402,7 @@ const b = { }); this.lockedOn = null - if (this.endCycle > game.cycle + this.deathCycles && b.isModDroneCollide) { + if (this.endCycle > game.cycle + this.deathCycles) { this.endCycle -= 60 if (game.cycle + this.deathCycles > this.endCycle) this.endCycle = game.cycle + this.deathCycles } @@ -2966,7 +2972,7 @@ const b = { } player.force.x -= knock * Math.cos(mech.angle) player.force.y -= knock * Math.sin(mech.angle) * 0.3 //reduce knock back in vertical direction to stop super jumps - if (b.isModShotgunImmune) mech.collisionImmuneCycle = mech.cycle + 60; //player is immune to collision damage for 30 cycles + if (b.isModShotgunImmune) mech.immuneCycle = mech.cycle + 60; //player is immune to collision damage for 30 cycles b.muzzleFlash(35); const side = 19 * b.modBulletSize for (let i = 0; i < 15; i++) { @@ -3687,11 +3693,15 @@ const b = { isStarterGun: false, isEasyToAim: true, fire() { - const speed = mech.crouch ? 36 : 22 - b.mine({ + const pos = { x: mech.pos.x + 30 * Math.cos(mech.angle), y: mech.pos.y + 30 * Math.sin(mech.angle) - }, { + } + let speed = mech.crouch ? 36 : 22 + if (Matter.Query.point(map, pos).length > 0) { //don't fire if mine will spawn inside map + speed = -2 + } + b.mine(pos, { x: speed * Math.cos(mech.angle), y: speed * Math.sin(mech.angle) }, 0, b.isModMineAmmoBack) @@ -3820,13 +3830,13 @@ const b = { name: "drones", description: "deploy drones that crash into mobs
collisions reduce their lifespan by 1 second", ammo: 0, - ammoPack: 14, + ammoPack: 15, have: false, isStarterGun: true, isEasyToAim: true, fire() { b.drone(mech.crouch ? 45 : 1) - mech.fireCDcycle = mech.cycle + Math.floor((mech.crouch ? 25 : 5) * b.modFireRate); // cool down + mech.fireCDcycle = mech.cycle + Math.floor((mech.crouch ? 13 : 5) * b.modFireRate); // cool down } }, { diff --git a/js/engine.js b/js/engine.js index 34b1d0e..9cf2e23 100644 --- a/js/engine.js +++ b/js/engine.js @@ -97,8 +97,7 @@ function collisionChecks(event) { function collidePlayer(obj) { //player dmg from hitting a body - // if ( mech.collisionImmuneCycle < mech.cycle) { - if (obj.classType === "body" && obj.speed > 10 && mech.collisionImmuneCycle < mech.cycle) { + if (obj.classType === "body" && obj.speed > 10 && mech.immuneCycle < mech.cycle) { const velocityThreshold = 30 //keep this lines up with player.enterLand numbers (130/5 = 26) if (player.position.y > obj.position.y) { //block is above the player look at total momentum difference const velocityDiffMag = Vector.magnitude(Vector.sub(player.velocity, obj.velocity)) @@ -109,7 +108,7 @@ function collisionChecks(event) { } function hit(dmg) { - mech.collisionImmuneCycle = mech.cycle + b.modCollisionImmuneCycles; //player is immune to collision damage for 30 cycles + mech.immuneCycle = mech.cycle + b.modCollisionImmuneCycles; //player is immune to collision damage for 30 cycles dmg = Math.min(Math.max(Math.sqrt(dmg) * obj.mass * 0.01, 0.02), 0.15); mech.damage(dmg); game.drawList.push({ //add dmg to draw queue @@ -123,27 +122,6 @@ function collisionChecks(event) { } } - // function collidePlayer(obj, speedThreshold = 12, massThreshold = 2) { - // //player dmg from hitting a body - // if (obj.classType === "body" && mech.collisionImmuneCycle < mech.cycle && obj.speed > speedThreshold && obj.mass > massThreshold) { - // const v = Vector.magnitude(Vector.sub(player.velocity, obj.velocity)); - // if ((Math.abs(obj.velocity.x - player.velocity.x) > speedThreshold) || (player.position.y > obj.position.y && v > speedThreshold)) { - // mech.collisionImmuneCycle = mech.cycle + b.modCollisionImmuneCycles; //player is immune to collision damage for 30 cycles - // let dmg = Math.sqrt((v - speedThreshold + 0.1) * (obj.mass - massThreshold)) * 0.01; - // dmg = Math.min(Math.max(dmg, 0.02), 0.15); - // mech.damage(dmg); - // game.drawList.push({ //add dmg to draw queue - // x: pairs[i].activeContacts[0].vertex.x, - // y: pairs[i].activeContacts[0].vertex.y, - // radius: dmg * 500, - // color: game.mobDmgColor, - // time: game.drawTime - // }); - // return; - // } - // } - // } - //mob + (player,bullet,body) collisions for (let k = 0; k < mob.length; k++) { if (mob[k].alive && mech.alive) { @@ -157,8 +135,8 @@ function collisionChecks(event) { function collideMob(obj) { //player + mob collision - if (mech.collisionImmuneCycle < mech.cycle && (obj === playerBody || obj === playerHead)) { - mech.collisionImmuneCycle = mech.cycle + b.modCollisionImmuneCycles; //player is immune to collision damage for 30 cycles + if (mech.immuneCycle < mech.cycle && (obj === playerBody || obj === playerHead)) { + mech.immuneCycle = mech.cycle + b.modCollisionImmuneCycles; //player is immune to collision damage for 30 cycles mob[k].foundPlayer(); let dmg = Math.min(Math.max(0.025 * Math.sqrt(mob[k].mass), 0.05), 0.3) * game.dmgScale; //player damage is capped at 0.3*dmgScale of 1.0 if (b.isModPiezo) { diff --git a/js/level.js b/js/level.js index 79126b2..76cdee6 100644 --- a/js/level.js +++ b/js/level.js @@ -17,9 +17,9 @@ const level = { // game.enableConstructMode() //used to build maps in testing mode // level.difficultyIncrease(9) // mech.setField("time dilation field") - // b.giveMod("many worlds"); - // b.giveGuns("neutron bomb") - // b.giveGuns("foam") + // b.giveMod("brushless motor"); + // b.giveGuns("drones") + // b.giveGuns("mine") // mech.setField("pilot wave") // mech.setField("phase decoherence field") @@ -135,7 +135,7 @@ const level = { spawn.mapRect(-250, -700, 1000, 900); // shelf spawn.mapRect(-250, -1200, 1000, 250); // shelf roof powerUps.spawnStartingPowerUps(600, -800); - powerUps.spawn(550, -800, "reroll", false); //starting gun + powerUps.spawn(550, -800, "reroll", false); function blockDoor(x, y, blockSize = 58) { spawn.mapRect(x, y - 290, 40, 60); // door lip diff --git a/js/mobs.js b/js/mobs.js index 9c1736b..4beba84 100644 --- a/js/mobs.js +++ b/js/mobs.js @@ -373,7 +373,7 @@ const mobs = { ctx.setLineDash([125 * Math.random(), 125 * Math.random()]); // ctx.lineDashOffset = 6*(game.cycle % 215); if (this.distanceToPlayer() < this.laserRange && !mech.isStealth) { - if (mech.collisionImmuneCycle < mech.cycle) mech.damage(0.0003 * game.dmgScale); + if (mech.immuneCycle < mech.cycle) mech.damage(0.0003 * game.dmgScale); if (mech.energy > 0.1) mech.energy -= 0.003 ctx.beginPath(); ctx.moveTo(this.position.x, this.position.y); @@ -461,13 +461,15 @@ const mobs = { if (!mech.isStealth) vertexCollision(this.position, look, [player]); // hitting player if (best.who === player) { - if (mech.collisionImmuneCycle < mech.cycle) dmg = 0.0012 * game.dmgScale; - mech.damage(dmg); - //draw damage - ctx.fillStyle = "#f00"; - ctx.beginPath(); - ctx.arc(best.x, best.y, dmg * 2000, 0, 2 * Math.PI); - ctx.fill(); + if (mech.immuneCycle < mech.cycle) { + const dmg = 0.0012 * game.dmgScale; + mech.damage(dmg); + //draw damage + ctx.fillStyle = "#f00"; + ctx.beginPath(); + ctx.arc(best.x, best.y, dmg * 2000, 0, 2 * Math.PI); + ctx.fill(); + } } //draw beam if (best.dist2 === Infinity) { diff --git a/js/player.js b/js/player.js index 60a195d..dcb3390 100644 --- a/js/player.js +++ b/js/player.js @@ -215,9 +215,6 @@ const mech = { mech.yOff = mech.yOffWhen.jump; mech.hardLandCD = mech.cycle + Math.min(momentum / 6.5 - 6, 40) - // if (b.isModStompPauli) { - // mech.collisionImmuneCycle = mech.cycle + b.modCollisionImmuneCycles; //player is immune to collision damage for 30 cycles - // } if (b.isModStomp) { const len = Math.min(25, (momentum - 120) * 0.1) for (let i = 0; i < len; i++) { @@ -363,7 +360,7 @@ const mech = { if (b.isModImmortal) { //if player has the immortality buff, spawn on the same level with randomized stats spawn.setSpawnList(); //new mob types game.clearNow = true; //triggers a map reset - powerUps.reroll.rerolls = Math.floor(Math.random() * Math.random() * 8) + powerUps.reroll.rerolls = Math.floor(Math.random() * Math.random() * 12) //count mods let totalMods = 0; @@ -511,7 +508,7 @@ const mech = { } }, defaultFPSCycle: 0, //tracks when to return to normal fps - collisionImmuneCycle: 0, //used in engine + immuneCycle: 0, //used in engine harmReduction() { let dmg = 1 dmg *= mech.fieldDamageResistance @@ -548,24 +545,23 @@ const mech = { if (b.isModEnergyHealth) { mech.energy -= dmg; if (mech.energy < 0 || isNaN(mech.energy)) { - if (b.isModDeathAvoid && !b.isModDeathAvoidOnCD) { //&& Math.random() < 0.5 - b.isModDeathAvoidOnCD = true; - mech.energy += dmg //undo the damage - if (mech.energy < 0.05) mech.energy = 0.05 - mech.collisionImmuneCycle = mech.cycle + 30 //disable this.collisionImmuneCycle bonus seconds + if (b.isModDeathAvoid && powerUps.reroll.rerolls) { //&& Math.random() < 0.5 + powerUps.reroll.changeRerolls(-1) + + mech.energy = mech.maxEnergy * 0.5 + // if (mech.energy < 0.05) mech.energy = 0.05 + mech.immuneCycle = mech.cycle + 120 //disable this.immuneCycle bonus seconds + game.makeTextLog(" death avoided
1 reroll consumed
", 300) game.wipe = function () { //set wipe to have trails - ctx.fillStyle = "rgba(255,255,255,0.02)"; + ctx.fillStyle = "rgba(255,255,255,0.03)"; ctx.fillRect(0, 0, canvas.width, canvas.height); } setTimeout(function () { game.wipe = function () { //set wipe to normal ctx.clearRect(0, 0, canvas.width, canvas.height); } - // game.replaceTextLog = true; - // game.makeTextLog("death avoided", 360); - b.isModDeathAvoidOnCD = false; - }, 3000); + }, 2000); return; } else { @@ -578,24 +574,22 @@ const mech = { } else { mech.health -= dmg; if (mech.health < 0 || isNaN(mech.health)) { - if (b.isModDeathAvoid && !b.isModDeathAvoidOnCD) { //&& Math.random() < 0.5 - b.isModDeathAvoidOnCD = true; - mech.health += dmg //undo the damage - if (mech.health < 0.05) mech.health = 0.05 - mech.collisionImmuneCycle = mech.cycle + 30 //disable this.collisionImmuneCycle bonus seconds + if (b.isModDeathAvoid && powerUps.reroll.rerolls > 0) { //&& Math.random() < 0.5 + powerUps.reroll.changeRerolls(-1) + mech.health = mech.maxHealth * 0.5 + // if (mech.health < 0.05) mech.health = 0.05 + mech.immuneCycle = mech.cycle + 120 //disable this.immuneCycle bonus seconds + game.makeTextLog(" death avoided
1 reroll consumed
", 300) game.wipe = function () { //set wipe to have trails - ctx.fillStyle = "rgba(255,255,255,0.02)"; + ctx.fillStyle = "rgba(255,255,255,0.03)"; ctx.fillRect(0, 0, canvas.width, canvas.height); } setTimeout(function () { game.wipe = function () { //set wipe to normal ctx.clearRect(0, 0, canvas.width, canvas.height); } - // game.replaceTextLog = true; - // game.makeTextLog("death avoided", 360); - b.isModDeathAvoidOnCD = false; - }, 3000); + }, 2000); } else { mech.health = 0; mech.death(); @@ -711,19 +705,12 @@ const mech = { // }, draw() { - // mech.fillColor = (mech.collisionImmuneCycle < mech.cycle) ? "#fff" : "rgba(255,255,255,0.1)" //"#cff" ctx.fillStyle = mech.fillColor; mech.walk_cycle += mech.flipLegs * mech.Vx; //draw body ctx.save(); - // if (mech.collisionImmuneCycle < mech.cycle) { - // ctx.globalAlpha = 1 - // if (mech.collisionImmune) mech.collisionImmune = false; - // } else { - // ctx.globalAlpha = 0.7 - // } - ctx.globalAlpha = (mech.collisionImmuneCycle < mech.cycle) ? 1 : 0.7 + ctx.globalAlpha = (mech.immuneCycle < mech.cycle) ? 1 : 0.7 ctx.translate(mech.pos.x, mech.pos.y); mech.calcLeg(Math.PI, -3); mech.drawLeg("#4a4a4a"); @@ -1672,8 +1659,8 @@ const mech = { const force = Vector.mult(Vector.normalise(Vector.sub(mech.pos, path[1])), -0.01 * Math.min(5, best.who.mass)) Matter.Body.applyForce(best.who, path[1], force) Matter.Body.setVelocity(best.who, { //friction - x: best.who.velocity.x * 0.6, - y: best.who.velocity.y * 0.6 + x: best.who.velocity.x * 0.7, + y: best.who.velocity.y * 0.7 }); // const angle = Math.atan2(player.position.y - best.who.position.y, player.position.x - best.who.position.x); // const mass = Math.min(Math.sqrt(best.who.mass), 6); diff --git a/js/powerups.js b/js/powerups.js index e0b0b9e..a6b0cd1 100644 --- a/js/powerups.js +++ b/js/powerups.js @@ -21,7 +21,7 @@ const powerUps = { powerUps.endDraft(); }, endDraft() { - if (b.manyWorlds) { + if (b.manyWorlds && Math.random() < 0.66) { powerUps.spawn(mech.pos.x, mech.pos.y, "reroll"); if (Math.random() < b.modBayesian) powerUps.spawn(mech.pos.x, mech.pos.y, "reroll"); } @@ -47,9 +47,16 @@ const powerUps = { return 20; }, effect() { - powerUps.reroll.rerolls++ + powerUps.reroll.changeRerolls(1) game.makeTextLog("
  +1 reroll", 300) }, + changeRerolls(amount) { + powerUps.reroll.rerolls += amount + if (powerUps.reroll.rerolls < 0) powerUps.reroll.rerolls = 0 + if (b.isModDeathAvoid && document.getElementById("mod-anthropic")) { + document.getElementById("mod-anthropic").innerHTML = `(${powerUps.reroll.rerolls})` + } + }, diceText() { const r = powerUps.reroll.rerolls const fullDice = Math.floor(r / 6) @@ -71,25 +78,8 @@ const powerUps = { } return out }, - // diceText() { - // if (powerUps.reroll.rerolls === 1) { - // return '⚀' - // } else if (powerUps.reroll.rerolls === 2) { - // return '⚁' - // } else if (powerUps.reroll.rerolls === 3) { - // return '⚂' - // } else if (powerUps.reroll.rerolls === 4) { - // return '⚃' - // } else if (powerUps.reroll.rerolls === 5) { - // return '⚄' - // } else if (powerUps.reroll.rerolls === 6) { - // return '⚅' - // } else if (powerUps.reroll.rerolls > 6) { - // return '⚅+' - // } - // }, use(type) { - powerUps.reroll.rerolls--; + powerUps.reroll.changeRerolls(-1) powerUps[type].effect(); }, }, @@ -153,13 +143,30 @@ const powerUps = { size() { return 45; }, + choiceLog: [], //records all previous choice options effect() { function pick(who, skip1 = -1, skip2 = -1, skip3 = -1, skip4 = -1) { let options = []; for (let i = 1; i < who.length; i++) { if (i !== mech.fieldMode && (!game.isEasyToAimMode || mech.fieldUpgrades[i].isEasyToAim) && i !== skip1 && i !== skip2 && i !== skip3 && i !== skip4) options.push(i); } - if (options.length > 0) return options[Math.floor(Math.random() * options.length)] + //remove repeats from last selection + const totalChoices = b.isModDeterminism ? 1 : 3 + b.isModExtraChoice * 2 + if (powerUps.field.choiceLog.length > totalChoices || powerUps.field.choiceLog.length === totalChoices) { //make sure this isn't the first time getting a power up and there are previous choices to remove + for (let i = 0; i < totalChoices; i++) { //repeat for each choice from the last selection + if (options.length > totalChoices) { + for (let j = 0, len = options.length; j < len; j++) { + if (powerUps.field.choiceLog[powerUps.field.choiceLog.length - 1 - i] === options[j]) { + options.splice(j, 1) //remove previous choice from option pool + break + } + } + } + } + } + if (options.length > 0) { + return options[Math.floor(Math.random() * options.length)] + } } let choice1 = pick(mech.fieldUpgrades) @@ -179,7 +186,13 @@ const powerUps = { if (choice4 > -1) text += `
  ${mech.fieldUpgrades[choice4].name}
${mech.fieldUpgrades[choice4].description}
` let choice5 = pick(mech.fieldUpgrades, choice1, choice2, choice3, choice4) if (choice5 > -1) text += `
  ${mech.fieldUpgrades[choice5].name}
${mech.fieldUpgrades[choice5].description}
` + powerUps.field.choiceLog.push(choice4) + powerUps.field.choiceLog.push(choice5) } + powerUps.field.choiceLog.push(choice1) + powerUps.field.choiceLog.push(choice2) + powerUps.field.choiceLog.push(choice3) + if (powerUps.reroll.rerolls) text += `
  reroll ${powerUps.reroll.diceText()}
` // text += `
${game.SVGrightMouse} activate the shield with the right mouse
fields shield you from damage
and let you pick up and throw blocks
` @@ -196,6 +209,7 @@ const powerUps = { size() { return 42; }, + choiceLog: [], //records all previous choice options effect() { function pick(skip1 = -1, skip2 = -1, skip3 = -1, skip4 = -1) { let options = []; @@ -204,7 +218,23 @@ const powerUps = { options.push(i); } } - if (options.length > 0) return options[Math.floor(Math.random() * options.length)] + //remove repeats from last selection + const totalChoices = b.isModDeterminism ? 1 : 3 + b.isModExtraChoice * 2 + if (powerUps.mod.choiceLog.length > totalChoices || powerUps.mod.choiceLog.length === totalChoices) { //make sure this isn't the first time getting a power up and there are previous choices to remove + for (let i = 0; i < totalChoices; i++) { //repeat for each choice from the last selection + if (options.length > totalChoices) { + for (let j = 0, len = options.length; j < len; j++) { + if (powerUps.mod.choiceLog[powerUps.mod.choiceLog.length - 1 - i] === options[j]) { + options.splice(j, 1) //remove previous choice from option pool + break + } + } + } + } + } + if (options.length > 0) { + return options[Math.floor(Math.random() * options.length)] + } } let choice1 = pick() @@ -224,7 +254,12 @@ const powerUps = { if (choice4 > -1) text += `
  ${b.mods[choice4].name}
${b.mods[choice4].description}
` let choice5 = pick(choice1, choice2, choice3, choice4) if (choice5 > -1) text += `
  ${b.mods[choice5].name}
${b.mods[choice5].description}
` + powerUps.mod.choiceLog.push(choice4) + powerUps.mod.choiceLog.push(choice5) } + powerUps.mod.choiceLog.push(choice1) + powerUps.mod.choiceLog.push(choice2) + powerUps.mod.choiceLog.push(choice3) if (powerUps.reroll.rerolls) text += `
  reroll ${powerUps.reroll.diceText()}
` document.getElementById("choose-grid").innerHTML = text @@ -240,13 +275,33 @@ const powerUps = { size() { return 35; }, + choiceLog: [], //records all previous choice options effect() { function pick(who, skip1 = -1, skip2 = -1, skip3 = -1, skip4 = -1) { let options = []; for (let i = 0; i < who.length; i++) { - if (!who[i].have && (!game.isEasyToAimMode || b.guns[i].isEasyToAim) && i !== skip1 && i !== skip2 && i !== skip3 && i !== skip4) options.push(i); + if (!who[i].have && (!game.isEasyToAimMode || b.guns[i].isEasyToAim) && i !== skip1 && i !== skip2 && i !== skip3 && i !== skip4) { + options.push(i); + } + } + + //remove repeats from last selection + const totalChoices = b.isModDeterminism ? 1 : 3 + b.isModExtraChoice * 2 + if (powerUps.gun.choiceLog.length > totalChoices || powerUps.gun.choiceLog.length === totalChoices) { //make sure this isn't the first time getting a power up and there are previous choices to remove + for (let i = 0; i < totalChoices; i++) { //repeat for each choice from the last selection + if (options.length > totalChoices) { + for (let j = 0, len = options.length; j < len; j++) { + if (powerUps.gun.choiceLog[powerUps.gun.choiceLog.length - 1 - i] === options[j]) { + options.splice(j, 1) //remove previous choice from option pool + break + } + } + } + } + } + if (options.length > 0) { + return options[Math.floor(Math.random() * options.length)] } - if (options.length > 0) return options[Math.floor(Math.random() * options.length)] } let choice1 = pick(b.guns) @@ -267,10 +322,17 @@ const powerUps = { let choice5 = pick(b.guns, choice1, choice2, choice3, choice4) if (choice5 > -1) text += `
  ${b.guns[choice5].name}
${b.guns[choice5].description}
` + powerUps.gun.choiceLog.push(choice4) + powerUps.gun.choiceLog.push(choice5) } - + powerUps.gun.choiceLog.push(choice1) + powerUps.gun.choiceLog.push(choice2) + powerUps.gun.choiceLog.push(choice3) if (powerUps.reroll.rerolls) text += `
  reroll ${powerUps.reroll.diceText()}
` + // console.log(powerUps.gun.choiceLog) + // console.log(choice1, choice2, choice3) + document.getElementById("choose-grid").innerHTML = text powerUps.showDraft(); } else { diff --git a/js/spawn.js b/js/spawn.js index 8c75c8c..d2e02ca 100644 --- a/js/spawn.js +++ b/js/spawn.js @@ -1019,8 +1019,8 @@ const spawn = { vertexCollision(where, look, map); vertexCollision(where, look, body); if (!mech.isStealth) vertexCollision(where, look, [player]); - if (best.who && best.who === player && mech.collisionImmuneCycle < mech.cycle) { - mech.collisionImmuneCycle = mech.cycle + b.modCollisionImmuneCycles; //player is immune to collision damage for 30 cycles + if (best.who && best.who === player && mech.immuneCycle < mech.cycle) { + mech.immuneCycle = mech.cycle + b.modCollisionImmuneCycles; //player is immune to collision damage for 30 cycles const dmg = 0.14 * game.dmgScale; mech.damage(dmg); game.drawList.push({ //add dmg to draw queue @@ -1445,7 +1445,7 @@ const spawn = { // Matter.Body.rotate(me, Math.PI) me.memory = 120; - me.fireFreq = 0.006 + Math.random() * 0.003; + me.fireFreq = 0.007 + Math.random() * 0.003; me.noseLength = 0; me.fireAngle = 0; me.accelMag = 0.0005 * game.accelScale; diff --git a/todo.txt b/todo.txt index 05c6f6a..a17cbf9 100644 --- a/todo.txt +++ b/todo.txt @@ -1,20 +1,24 @@ -mod - many worlds: spawn a reroll after choosing (or canceling) a power up -new mob type - launcher: similar to the shooter, but fires bullets that chase you -plasma torch - reduces harm to player by 1/3 and has more reliable stopping power against charging mobs -explosions and neutron bomb do 50% less damage through walls -drone bullets bounce off mobs more predictably +anthropic principle - now consumes 1 rerolls, and heals player to 50% health instead of letting them die +many worlds - 66% chance for rerolls +quantum immortality - also gives 3 rerolls +mod drones - Brushless Motor: drones move faster +mod drones - redundant systems: removed +choices in power up selection should no longer repeat the previous choices when possible ************** TODO - n-gon ************** -what about a neutron bomb mod, that cause the bomb to activate right after you fire and slowly move forward with no gravity +bug - mines spawn extra mines when fired at thin map wall while jumping -Drop a reroll when the player exits the selection screen without picking one of the choices +mod - negative mass field move faster + less friction, more like flying? + +what about a neutron bomb mod, that causes the bomb to activate right after you fire and slowly move forward with no gravity redblobgames.com/articles/visibility https://github.com/Silverwolf90/2d-visibility/tree/master/src could apply to explosions, neutron bomb, player LOS -sticking bullets don't always gain the correct speed from mobs after they die +bug - sticking bullets don't always gain the correct speed from mobs after they die possible names for mods Hypergolic - A hypergolic propellant combination used in a rocket engine is one whose components spontaneously ignite when they come into contact with each other.