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
This commit is contained in:
landgreen
2020-05-16 09:46:43 -07:00
parent 30518de6cb
commit 0ff8021ea8
8 changed files with 215 additions and 172 deletions

View File

@@ -36,7 +36,7 @@ const b = {
modCollisionImmuneCycles: null, modCollisionImmuneCycles: null,
modBlockDmg: null, modBlockDmg: null,
isModPiezo: null, isModPiezo: null,
isModDroneCollide: null, isModFastDrones: null,
isModFastSpores: null, isModFastSpores: null,
modSuperBallNumber: null, modSuperBallNumber: null,
modOneSuperBall: null, modOneSuperBall: null,
@@ -49,7 +49,6 @@ const b = {
isModHealthRecovery: null, isModHealthRecovery: null,
isModEnergyLoss: null, isModEnergyLoss: null,
isModDeathAvoid: null, isModDeathAvoid: null,
isModDeathAvoidOnCD: null,
modWaveSpeedMap: null, modWaveSpeedMap: null,
modWaveSpeedBody: null, modWaveSpeedBody: null,
isModSporeField: null, isModSporeField: null,
@@ -531,7 +530,7 @@ const b = {
}, },
{ {
name: "Pauli exclusion", name: "Pauli exclusion",
description: `unable to <strong>collide</strong> with mobs for <strong>+2</strong> seconds<br>activates after being <strong>harmed</strong> from a collision`, description: `<strong>immune</strong> to <strong>harm</strong> for <strong>+1</strong> seconds<br>activates after being <strong>harmed</strong> from a collision`,
maxCount: 9, maxCount: 9,
count: 0, count: 0,
allowed() { allowed() {
@@ -539,8 +538,8 @@ const b = {
}, },
requires: "", requires: "",
effect() { effect() {
b.modCollisionImmuneCycles += 120; b.modCollisionImmuneCycles += 60;
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
}, },
remove() { remove() {
b.modCollisionImmuneCycles = 30; b.modCollisionImmuneCycles = 30;
@@ -562,40 +561,6 @@ const b = {
b.isModSlowFPS = false; b.isModSlowFPS = false;
} }
}, },
{
name: "quantum immortality",
description: "after <strong>dying</strong>, continue in an <strong>alternate reality</strong><br><em>guns, ammo, field, and mods are randomized</em>",
maxCount: 1,
count: 0,
allowed() {
return true
},
requires: "",
effect() {
b.isModImmortal = true;
},
remove() {
b.isModImmortal = false;
}
},
{
name: "anthropic principle",
description: "<strong>fatal harm</strong> can't happen<br><strong>saves</strong> you up to once every <strong>3</strong> 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", name: "entanglement",
nameInfo: "<span id = 'mod-entanglement'></span>", nameInfo: "<span id = 'mod-entanglement'></span>",
@@ -780,7 +745,7 @@ const b = {
}, },
{ {
name: "Bayesian inference", name: "Bayesian inference",
description: "<strong>33%</strong> chance for double <strong>power ups</strong> to drop<br><strong>remove</strong> all future <strong>ammo</strong> power ups", description: "<strong>37%</strong> chance for double <strong>power ups</strong> to drop<br><strong>remove</strong> all future <strong>ammo</strong> power ups",
maxCount: 1, maxCount: 1,
count: 0, count: 0,
allowed() { allowed() {
@@ -788,7 +753,7 @@ const b = {
}, },
requires: "", requires: "",
effect: () => { effect: () => {
b.modBayesian = 0.33; b.modBayesian = 0.37;
}, },
remove() { remove() {
b.modBayesian = 0; b.modBayesian = 0;
@@ -828,7 +793,7 @@ const b = {
}, },
{ {
name: "determinism", name: "determinism",
description: "spawn <strong>4</strong> <strong class='color-m'>mods</strong> and 2 <strong class='color-h'>heal</strong> power ups<br>future <strong>power ups</strong> are limited to <strong>one choice</strong>", description: "spawn <strong>5</strong> <strong class='color-m'>mods</strong> and 2 <strong class='color-h'>heal</strong> power ups<br>future <strong>power ups</strong> are limited to <strong>one choice</strong>",
maxCount: 1, maxCount: 1,
count: 0, count: 0,
allowed() { allowed() {
@@ -837,7 +802,7 @@ const b = {
requires: "not cardinality", requires: "not cardinality",
effect: () => { effect: () => {
b.isModDeterminism = true; 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"); powerUps.spawn(mech.pos.x, mech.pos.y, "mod");
if (Math.random() < b.modBayesian) 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", name: "many worlds",
description: "spawn a <strong class='color-r'>reroll</strong> after choosing a power up", description: "after choosing a <strong>gun</strong>, <strong>field</strong>, or <strong class='color-m'>mod</strong><br><strong>66%</strong> chance to spawn a <strong class='color-r'>reroll</strong>",
maxCount: 1, maxCount: 1,
count: 0, count: 0,
allowed() { allowed() {
@@ -870,6 +835,45 @@ const b = {
b.manyWorlds = false; b.manyWorlds = false;
} }
}, },
{
name: "anthropic principle",
nameInfo: "<span id = 'mod-anthropic'></span>",
description: "<strong class='color-h'>heal</strong> to <strong>50%</strong> health instead of <strong>dying</strong><br>consumes <strong>1</strong> <strong class='color-r'>reroll</strong>",
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 <strong>dying</strong>, continue in an <strong>alternate reality</strong><br>spawn <strong>3</strong> <strong class='color-r'>rerolls</strong>",
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", name: "Born rule",
description: "<strong>remove</strong> all current <strong class='color-m'>mods</strong><br>spawn new <strong class='color-m'>mods</strong> to replace them", description: "<strong>remove</strong> all current <strong class='color-m'>mods</strong><br>spawn new <strong class='color-m'>mods</strong> to replace them",
@@ -991,7 +995,7 @@ const b = {
}, },
{ {
name: "shotgun spin-statistics", name: "shotgun spin-statistics",
description: "firing the <strong>shotgun</strong> makes you <br><strong>immune</strong> to collisions for <strong>1 second</strong>", description: "firing the <strong>shotgun</strong> makes you <br><strong>immune</strong> to <strong>harm</strong> for <strong>1 second</strong>",
maxCount: 1, maxCount: 1,
count: 0, count: 0,
allowed() { allowed() {
@@ -1364,8 +1368,8 @@ const b = {
} }
}, },
{ {
name: "redundant systems", name: "brushless motor",
description: "<strong>drone</strong> collisions no longer reduce their <strong>lifespan</strong>", description: "<strong>drones</strong> accelerate <strong>50%</strong> faster",
maxCount: 1, maxCount: 1,
count: 0, count: 0,
allowed() { allowed() {
@@ -1373,10 +1377,10 @@ const b = {
}, },
requires: "drones", requires: "drones",
effect() { effect() {
b.isModDroneCollide = true b.isModFastDrones = true
}, },
remove() { 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 let collide = Matter.Query.collides(this, map) //check if collides with map
if (collide.length > 0) { if (collide.length > 0) {
for (let i = 0; i < collide.length; i++) { 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, { const angle = Matter.Vector.angle(collide[i].normal, {
x: 1, x: 1,
y: 0 y: 0
@@ -2141,7 +2145,7 @@ const b = {
Matter.Body.setAngle(this, Math.atan2(collide[i].tangent.y, collide[i].tangent.x)) Matter.Body.setAngle(this, Math.atan2(collide[i].tangent.y, collide[i].tangent.x))
//move until touching map again after rotation //move until touching map again after rotation
for (let j = 0; j < 10; j++) { 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 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 Matter.Body.setStatic(this, true) //don't set to static if not touching map
} else { } else {
@@ -2156,7 +2160,8 @@ const b = {
//sometimes the mine can't attach to map and it just needs to be reset //sometimes the mine can't attach to map and it just needs to be reset
const that = this const that = this
setTimeout(function () { 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.endCycle = 0 // if not touching map explode
that.isArmed = false that.isArmed = false
b.mine(that.position, that.velocity, that.angle) b.mine(that.position, that.velocity, that.angle)
@@ -2366,17 +2371,18 @@ const b = {
}, },
drone(speed = 1) { drone(speed = 1) {
const me = bullet.length; const me = bullet.length;
const THRUST = 0.0015 const THRUST = b.isModFastDrones ? 0.0025 : 0.0015
const dir = mech.angle + 0.2 * (Math.random() - 0.5); 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()) 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, { bullet[me] = Bodies.polygon(mech.pos.x + 30 * Math.cos(mech.angle), mech.pos.y + 30 * Math.sin(mech.angle), 8, RADIUS, {
angle: dir, angle: dir,
inertia: Infinity, inertia: Infinity,
friction: 0.05, friction: 0.05,
frictionAir: 0.0005, frictionAir: FRICTION,
restitution: 1, restitution: 1,
dmg: 0.23, //damage done in addition to the damage from momentum 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), endCycle: game.cycle + Math.floor((1200 + 420 * Math.random()) * b.isModBulletsLastLonger),
classType: "bullet", classType: "bullet",
collisionFilter: { collisionFilter: {
@@ -2396,7 +2402,7 @@ const b = {
}); });
this.lockedOn = null this.lockedOn = null
if (this.endCycle > game.cycle + this.deathCycles && b.isModDroneCollide) { if (this.endCycle > game.cycle + this.deathCycles) {
this.endCycle -= 60 this.endCycle -= 60
if (game.cycle + this.deathCycles > this.endCycle) this.endCycle = game.cycle + this.deathCycles 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.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 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); b.muzzleFlash(35);
const side = 19 * b.modBulletSize const side = 19 * b.modBulletSize
for (let i = 0; i < 15; i++) { for (let i = 0; i < 15; i++) {
@@ -3687,11 +3693,15 @@ const b = {
isStarterGun: false, isStarterGun: false,
isEasyToAim: true, isEasyToAim: true,
fire() { fire() {
const speed = mech.crouch ? 36 : 22 const pos = {
b.mine({
x: mech.pos.x + 30 * Math.cos(mech.angle), x: mech.pos.x + 30 * Math.cos(mech.angle),
y: mech.pos.y + 30 * Math.sin(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), x: speed * Math.cos(mech.angle),
y: speed * Math.sin(mech.angle) y: speed * Math.sin(mech.angle)
}, 0, b.isModMineAmmoBack) }, 0, b.isModMineAmmoBack)
@@ -3820,13 +3830,13 @@ const b = {
name: "drones", name: "drones",
description: "deploy drones that <strong>crash</strong> into mobs<br>collisions reduce their <strong>lifespan</strong> by 1 second", description: "deploy drones that <strong>crash</strong> into mobs<br>collisions reduce their <strong>lifespan</strong> by 1 second",
ammo: 0, ammo: 0,
ammoPack: 14, ammoPack: 15,
have: false, have: false,
isStarterGun: true, isStarterGun: true,
isEasyToAim: true, isEasyToAim: true,
fire() { fire() {
b.drone(mech.crouch ? 45 : 1) 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
} }
}, },
{ {

View File

@@ -97,8 +97,7 @@ function collisionChecks(event) {
function collidePlayer(obj) { function collidePlayer(obj) {
//player dmg from hitting a body //player dmg from hitting a body
// if ( mech.collisionImmuneCycle < mech.cycle) { if (obj.classType === "body" && obj.speed > 10 && mech.immuneCycle < mech.cycle) {
if (obj.classType === "body" && obj.speed > 10 && mech.collisionImmuneCycle < mech.cycle) {
const velocityThreshold = 30 //keep this lines up with player.enterLand numbers (130/5 = 26) 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 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)) const velocityDiffMag = Vector.magnitude(Vector.sub(player.velocity, obj.velocity))
@@ -109,7 +108,7 @@ function collisionChecks(event) {
} }
function hit(dmg) { 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); dmg = Math.min(Math.max(Math.sqrt(dmg) * obj.mass * 0.01, 0.02), 0.15);
mech.damage(dmg); mech.damage(dmg);
game.drawList.push({ //add dmg to draw queue 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 //mob + (player,bullet,body) collisions
for (let k = 0; k < mob.length; k++) { for (let k = 0; k < mob.length; k++) {
if (mob[k].alive && mech.alive) { if (mob[k].alive && mech.alive) {
@@ -157,8 +135,8 @@ function collisionChecks(event) {
function collideMob(obj) { function collideMob(obj) {
//player + mob collision //player + mob collision
if (mech.collisionImmuneCycle < mech.cycle && (obj === playerBody || obj === playerHead)) { if (mech.immuneCycle < mech.cycle && (obj === playerBody || obj === playerHead)) {
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
mob[k].foundPlayer(); 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 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) { if (b.isModPiezo) {

View File

@@ -17,9 +17,9 @@ const level = {
// game.enableConstructMode() //used to build maps in testing mode // game.enableConstructMode() //used to build maps in testing mode
// level.difficultyIncrease(9) // level.difficultyIncrease(9)
// mech.setField("time dilation field") // mech.setField("time dilation field")
// b.giveMod("many worlds"); // b.giveMod("brushless motor");
// b.giveGuns("neutron bomb") // b.giveGuns("drones")
// b.giveGuns("foam") // b.giveGuns("mine")
// mech.setField("pilot wave") // mech.setField("pilot wave")
// mech.setField("phase decoherence field") // mech.setField("phase decoherence field")
@@ -135,7 +135,7 @@ const level = {
spawn.mapRect(-250, -700, 1000, 900); // shelf spawn.mapRect(-250, -700, 1000, 900); // shelf
spawn.mapRect(-250, -1200, 1000, 250); // shelf roof spawn.mapRect(-250, -1200, 1000, 250); // shelf roof
powerUps.spawnStartingPowerUps(600, -800); powerUps.spawnStartingPowerUps(600, -800);
powerUps.spawn(550, -800, "reroll", false); //starting gun powerUps.spawn(550, -800, "reroll", false);
function blockDoor(x, y, blockSize = 58) { function blockDoor(x, y, blockSize = 58) {
spawn.mapRect(x, y - 290, 40, 60); // door lip spawn.mapRect(x, y - 290, 40, 60); // door lip

View File

@@ -373,7 +373,7 @@ const mobs = {
ctx.setLineDash([125 * Math.random(), 125 * Math.random()]); ctx.setLineDash([125 * Math.random(), 125 * Math.random()]);
// ctx.lineDashOffset = 6*(game.cycle % 215); // ctx.lineDashOffset = 6*(game.cycle % 215);
if (this.distanceToPlayer() < this.laserRange && !mech.isStealth) { 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 if (mech.energy > 0.1) mech.energy -= 0.003
ctx.beginPath(); ctx.beginPath();
ctx.moveTo(this.position.x, this.position.y); ctx.moveTo(this.position.x, this.position.y);
@@ -461,13 +461,15 @@ const mobs = {
if (!mech.isStealth) vertexCollision(this.position, look, [player]); if (!mech.isStealth) vertexCollision(this.position, look, [player]);
// hitting player // hitting player
if (best.who === player) { if (best.who === player) {
if (mech.collisionImmuneCycle < mech.cycle) dmg = 0.0012 * game.dmgScale; if (mech.immuneCycle < mech.cycle) {
mech.damage(dmg); const dmg = 0.0012 * game.dmgScale;
//draw damage mech.damage(dmg);
ctx.fillStyle = "#f00"; //draw damage
ctx.beginPath(); ctx.fillStyle = "#f00";
ctx.arc(best.x, best.y, dmg * 2000, 0, 2 * Math.PI); ctx.beginPath();
ctx.fill(); ctx.arc(best.x, best.y, dmg * 2000, 0, 2 * Math.PI);
ctx.fill();
}
} }
//draw beam //draw beam
if (best.dist2 === Infinity) { if (best.dist2 === Infinity) {

View File

@@ -215,9 +215,6 @@ const mech = {
mech.yOff = mech.yOffWhen.jump; mech.yOff = mech.yOffWhen.jump;
mech.hardLandCD = mech.cycle + Math.min(momentum / 6.5 - 6, 40) 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) { if (b.isModStomp) {
const len = Math.min(25, (momentum - 120) * 0.1) const len = Math.min(25, (momentum - 120) * 0.1)
for (let i = 0; i < len; i++) { 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 if (b.isModImmortal) { //if player has the immortality buff, spawn on the same level with randomized stats
spawn.setSpawnList(); //new mob types spawn.setSpawnList(); //new mob types
game.clearNow = true; //triggers a map reset 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 //count mods
let totalMods = 0; let totalMods = 0;
@@ -511,7 +508,7 @@ const mech = {
} }
}, },
defaultFPSCycle: 0, //tracks when to return to normal fps defaultFPSCycle: 0, //tracks when to return to normal fps
collisionImmuneCycle: 0, //used in engine immuneCycle: 0, //used in engine
harmReduction() { harmReduction() {
let dmg = 1 let dmg = 1
dmg *= mech.fieldDamageResistance dmg *= mech.fieldDamageResistance
@@ -548,24 +545,23 @@ const mech = {
if (b.isModEnergyHealth) { if (b.isModEnergyHealth) {
mech.energy -= dmg; mech.energy -= dmg;
if (mech.energy < 0 || isNaN(mech.energy)) { if (mech.energy < 0 || isNaN(mech.energy)) {
if (b.isModDeathAvoid && !b.isModDeathAvoidOnCD) { //&& Math.random() < 0.5 if (b.isModDeathAvoid && powerUps.reroll.rerolls) { //&& Math.random() < 0.5
b.isModDeathAvoidOnCD = true; powerUps.reroll.changeRerolls(-1)
mech.energy += dmg //undo the damage
if (mech.energy < 0.05) mech.energy = 0.05 mech.energy = mech.maxEnergy * 0.5
mech.collisionImmuneCycle = mech.cycle + 30 //disable this.collisionImmuneCycle bonus seconds // if (mech.energy < 0.05) mech.energy = 0.05
mech.immuneCycle = mech.cycle + 120 //disable this.immuneCycle bonus seconds
game.makeTextLog("<span style='font-size:115%;'> <strong>death</strong> avoided<br><strong>1</strong> <strong class='color-r'>reroll</strong> consumed</span>", 300)
game.wipe = function () { //set wipe to have trails 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); ctx.fillRect(0, 0, canvas.width, canvas.height);
} }
setTimeout(function () { setTimeout(function () {
game.wipe = function () { //set wipe to normal game.wipe = function () { //set wipe to normal
ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.clearRect(0, 0, canvas.width, canvas.height);
} }
// game.replaceTextLog = true; }, 2000);
// game.makeTextLog("death avoided", 360);
b.isModDeathAvoidOnCD = false;
}, 3000);
return; return;
} else { } else {
@@ -578,24 +574,22 @@ const mech = {
} else { } else {
mech.health -= dmg; mech.health -= dmg;
if (mech.health < 0 || isNaN(mech.health)) { if (mech.health < 0 || isNaN(mech.health)) {
if (b.isModDeathAvoid && !b.isModDeathAvoidOnCD) { //&& Math.random() < 0.5 if (b.isModDeathAvoid && powerUps.reroll.rerolls > 0) { //&& Math.random() < 0.5
b.isModDeathAvoidOnCD = true; powerUps.reroll.changeRerolls(-1)
mech.health += dmg //undo the damage mech.health = mech.maxHealth * 0.5
if (mech.health < 0.05) mech.health = 0.05 // if (mech.health < 0.05) mech.health = 0.05
mech.collisionImmuneCycle = mech.cycle + 30 //disable this.collisionImmuneCycle bonus seconds mech.immuneCycle = mech.cycle + 120 //disable this.immuneCycle bonus seconds
game.makeTextLog("<span style='font-size:115%;'> <strong>death</strong> avoided<br><strong>1</strong> <strong class='color-r'>reroll</strong> consumed</span>", 300)
game.wipe = function () { //set wipe to have trails 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); ctx.fillRect(0, 0, canvas.width, canvas.height);
} }
setTimeout(function () { setTimeout(function () {
game.wipe = function () { //set wipe to normal game.wipe = function () { //set wipe to normal
ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.clearRect(0, 0, canvas.width, canvas.height);
} }
// game.replaceTextLog = true; }, 2000);
// game.makeTextLog("death avoided", 360);
b.isModDeathAvoidOnCD = false;
}, 3000);
} else { } else {
mech.health = 0; mech.health = 0;
mech.death(); mech.death();
@@ -711,19 +705,12 @@ const mech = {
// }, // },
draw() { draw() {
// mech.fillColor = (mech.collisionImmuneCycle < mech.cycle) ? "#fff" : "rgba(255,255,255,0.1)" //"#cff"
ctx.fillStyle = mech.fillColor; ctx.fillStyle = mech.fillColor;
mech.walk_cycle += mech.flipLegs * mech.Vx; mech.walk_cycle += mech.flipLegs * mech.Vx;
//draw body //draw body
ctx.save(); ctx.save();
// if (mech.collisionImmuneCycle < mech.cycle) { ctx.globalAlpha = (mech.immuneCycle < mech.cycle) ? 1 : 0.7
// ctx.globalAlpha = 1
// if (mech.collisionImmune) mech.collisionImmune = false;
// } else {
// ctx.globalAlpha = 0.7
// }
ctx.globalAlpha = (mech.collisionImmuneCycle < mech.cycle) ? 1 : 0.7
ctx.translate(mech.pos.x, mech.pos.y); ctx.translate(mech.pos.x, mech.pos.y);
mech.calcLeg(Math.PI, -3); mech.calcLeg(Math.PI, -3);
mech.drawLeg("#4a4a4a"); 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)) 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.applyForce(best.who, path[1], force)
Matter.Body.setVelocity(best.who, { //friction Matter.Body.setVelocity(best.who, { //friction
x: best.who.velocity.x * 0.6, x: best.who.velocity.x * 0.7,
y: best.who.velocity.y * 0.6 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 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); // const mass = Math.min(Math.sqrt(best.who.mass), 6);

View File

@@ -21,7 +21,7 @@ const powerUps = {
powerUps.endDraft(); powerUps.endDraft();
}, },
endDraft() { endDraft() {
if (b.manyWorlds) { if (b.manyWorlds && Math.random() < 0.66) {
powerUps.spawn(mech.pos.x, mech.pos.y, "reroll"); powerUps.spawn(mech.pos.x, mech.pos.y, "reroll");
if (Math.random() < b.modBayesian) 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; return 20;
}, },
effect() { effect() {
powerUps.reroll.rerolls++ powerUps.reroll.changeRerolls(1)
game.makeTextLog("<div class='circle reroll'></div> &nbsp; <span style='font-size:115%;'> <strong>+1 reroll</strong></span>", 300) game.makeTextLog("<div class='circle reroll'></div> &nbsp; <span style='font-size:115%;'> <strong>+1 reroll</strong></span>", 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() { diceText() {
const r = powerUps.reroll.rerolls const r = powerUps.reroll.rerolls
const fullDice = Math.floor(r / 6) const fullDice = Math.floor(r / 6)
@@ -71,25 +78,8 @@ const powerUps = {
} }
return out 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) { use(type) {
powerUps.reroll.rerolls--; powerUps.reroll.changeRerolls(-1)
powerUps[type].effect(); powerUps[type].effect();
}, },
}, },
@@ -153,13 +143,30 @@ const powerUps = {
size() { size() {
return 45; return 45;
}, },
choiceLog: [], //records all previous choice options
effect() { effect() {
function pick(who, skip1 = -1, skip2 = -1, skip3 = -1, skip4 = -1) { function pick(who, skip1 = -1, skip2 = -1, skip3 = -1, skip4 = -1) {
let options = []; let options = [];
for (let i = 1; i < who.length; i++) { 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 (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) let choice1 = pick(mech.fieldUpgrades)
@@ -179,7 +186,13 @@ const powerUps = {
if (choice4 > -1) text += `<div class="choose-grid-module" onclick="powerUps.choose('field',${choice4})"><div class="grid-title"><div class="circle-grid field"></div> &nbsp; ${mech.fieldUpgrades[choice4].name}</div> ${mech.fieldUpgrades[choice4].description}</div>` if (choice4 > -1) text += `<div class="choose-grid-module" onclick="powerUps.choose('field',${choice4})"><div class="grid-title"><div class="circle-grid field"></div> &nbsp; ${mech.fieldUpgrades[choice4].name}</div> ${mech.fieldUpgrades[choice4].description}</div>`
let choice5 = pick(mech.fieldUpgrades, choice1, choice2, choice3, choice4) let choice5 = pick(mech.fieldUpgrades, choice1, choice2, choice3, choice4)
if (choice5 > -1) text += `<div class="choose-grid-module" onclick="powerUps.choose('field',${choice5})"><div class="grid-title"><div class="circle-grid field"></div> &nbsp; ${mech.fieldUpgrades[choice5].name}</div> ${mech.fieldUpgrades[choice5].description}</div>` if (choice5 > -1) text += `<div class="choose-grid-module" onclick="powerUps.choose('field',${choice5})"><div class="grid-title"><div class="circle-grid field"></div> &nbsp; ${mech.fieldUpgrades[choice5].name}</div> ${mech.fieldUpgrades[choice5].description}</div>`
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 += `<div class="choose-grid-module" onclick="powerUps.reroll.use('field')"><div class="grid-title"><div class="circle-grid reroll"></div> &nbsp; reroll <span class='dice'>${powerUps.reroll.diceText()}</span></div></div>` if (powerUps.reroll.rerolls) text += `<div class="choose-grid-module" onclick="powerUps.reroll.use('field')"><div class="grid-title"><div class="circle-grid reroll"></div> &nbsp; reroll <span class='dice'>${powerUps.reroll.diceText()}</span></div></div>`
// text += `<div style = 'color:#fff'>${game.SVGrightMouse} activate the shield with the right mouse<br>fields shield you from damage <br>and let you pick up and throw blocks</div>` // text += `<div style = 'color:#fff'>${game.SVGrightMouse} activate the shield with the right mouse<br>fields shield you from damage <br>and let you pick up and throw blocks</div>`
@@ -196,6 +209,7 @@ const powerUps = {
size() { size() {
return 42; return 42;
}, },
choiceLog: [], //records all previous choice options
effect() { effect() {
function pick(skip1 = -1, skip2 = -1, skip3 = -1, skip4 = -1) { function pick(skip1 = -1, skip2 = -1, skip3 = -1, skip4 = -1) {
let options = []; let options = [];
@@ -204,7 +218,23 @@ const powerUps = {
options.push(i); 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() let choice1 = pick()
@@ -224,7 +254,12 @@ const powerUps = {
if (choice4 > -1) text += `<div class="choose-grid-module" onclick="powerUps.choose('mod',${choice4})"><div class="grid-title"><div class="circle-grid mod"></div> &nbsp; ${b.mods[choice4].name}</div> ${b.mods[choice4].description}</div>` if (choice4 > -1) text += `<div class="choose-grid-module" onclick="powerUps.choose('mod',${choice4})"><div class="grid-title"><div class="circle-grid mod"></div> &nbsp; ${b.mods[choice4].name}</div> ${b.mods[choice4].description}</div>`
let choice5 = pick(choice1, choice2, choice3, choice4) let choice5 = pick(choice1, choice2, choice3, choice4)
if (choice5 > -1) text += `<div class="choose-grid-module" onclick="powerUps.choose('mod',${choice5})"><div class="grid-title"><div class="circle-grid mod"></div> &nbsp; ${b.mods[choice5].name}</div> ${b.mods[choice5].description}</div>` if (choice5 > -1) text += `<div class="choose-grid-module" onclick="powerUps.choose('mod',${choice5})"><div class="grid-title"><div class="circle-grid mod"></div> &nbsp; ${b.mods[choice5].name}</div> ${b.mods[choice5].description}</div>`
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 += `<div class="choose-grid-module" onclick="powerUps.reroll.use('mod')"><div class="grid-title"><div class="circle-grid reroll"></div> &nbsp; reroll <span class='dice'>${powerUps.reroll.diceText()}</span></div></div>` if (powerUps.reroll.rerolls) text += `<div class="choose-grid-module" onclick="powerUps.reroll.use('mod')"><div class="grid-title"><div class="circle-grid reroll"></div> &nbsp; reroll <span class='dice'>${powerUps.reroll.diceText()}</span></div></div>`
document.getElementById("choose-grid").innerHTML = text document.getElementById("choose-grid").innerHTML = text
@@ -240,13 +275,33 @@ const powerUps = {
size() { size() {
return 35; return 35;
}, },
choiceLog: [], //records all previous choice options
effect() { effect() {
function pick(who, skip1 = -1, skip2 = -1, skip3 = -1, skip4 = -1) { function pick(who, skip1 = -1, skip2 = -1, skip3 = -1, skip4 = -1) {
let options = []; let options = [];
for (let i = 0; i < who.length; i++) { 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) let choice1 = pick(b.guns)
@@ -267,10 +322,17 @@ const powerUps = {
let choice5 = pick(b.guns, choice1, choice2, choice3, choice4) let choice5 = pick(b.guns, choice1, choice2, choice3, choice4)
if (choice5 > -1) text += `<div class="choose-grid-module" onclick="powerUps.choose('gun',${choice5})"> if (choice5 > -1) text += `<div class="choose-grid-module" onclick="powerUps.choose('gun',${choice5})">
<div class="grid-title"><div class="circle-grid gun"></div> &nbsp; ${b.guns[choice5].name}</div> ${b.guns[choice5].description}</div>` <div class="grid-title"><div class="circle-grid gun"></div> &nbsp; ${b.guns[choice5].name}</div> ${b.guns[choice5].description}</div>`
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 += `<div class="choose-grid-module" onclick="powerUps.reroll.use('gun')"><div class="grid-title"><div class="circle-grid reroll"></div> &nbsp; reroll <span class='dice'>${powerUps.reroll.diceText()}</span></div></div>` if (powerUps.reroll.rerolls) text += `<div class="choose-grid-module" onclick="powerUps.reroll.use('gun')"><div class="grid-title"><div class="circle-grid reroll"></div> &nbsp; reroll <span class='dice'>${powerUps.reroll.diceText()}</span></div></div>`
// console.log(powerUps.gun.choiceLog)
// console.log(choice1, choice2, choice3)
document.getElementById("choose-grid").innerHTML = text document.getElementById("choose-grid").innerHTML = text
powerUps.showDraft(); powerUps.showDraft();
} else { } else {

View File

@@ -1019,8 +1019,8 @@ const spawn = {
vertexCollision(where, look, map); vertexCollision(where, look, map);
vertexCollision(where, look, body); vertexCollision(where, look, body);
if (!mech.isStealth) vertexCollision(where, look, [player]); if (!mech.isStealth) vertexCollision(where, look, [player]);
if (best.who && best.who === player && mech.collisionImmuneCycle < mech.cycle) { if (best.who && best.who === player && mech.immuneCycle < mech.cycle) {
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
const dmg = 0.14 * game.dmgScale; const dmg = 0.14 * game.dmgScale;
mech.damage(dmg); mech.damage(dmg);
game.drawList.push({ //add dmg to draw queue game.drawList.push({ //add dmg to draw queue
@@ -1445,7 +1445,7 @@ const spawn = {
// Matter.Body.rotate(me, Math.PI) // Matter.Body.rotate(me, Math.PI)
me.memory = 120; me.memory = 120;
me.fireFreq = 0.006 + Math.random() * 0.003; me.fireFreq = 0.007 + Math.random() * 0.003;
me.noseLength = 0; me.noseLength = 0;
me.fireAngle = 0; me.fireAngle = 0;
me.accelMag = 0.0005 * game.accelScale; me.accelMag = 0.0005 * game.accelScale;

View File

@@ -1,20 +1,24 @@
mod - many worlds: spawn a reroll after choosing (or canceling) a power up anthropic principle - now consumes 1 rerolls, and heals player to 50% health instead of letting them die
new mob type - launcher: similar to the shooter, but fires bullets that chase you many worlds - 66% chance for rerolls
plasma torch - reduces harm to player by 1/3 and has more reliable stopping power against charging mobs quantum immortality - also gives 3 rerolls
explosions and neutron bomb do 50% less damage through walls mod drones - Brushless Motor: drones move faster
drone bullets bounce off mobs more predictably mod drones - redundant systems: removed
choices in power up selection should no longer repeat the previous choices when possible
************** TODO - n-gon ************** ************** 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 redblobgames.com/articles/visibility
https://github.com/Silverwolf90/2d-visibility/tree/master/src https://github.com/Silverwolf90/2d-visibility/tree/master/src
could apply to explosions, neutron bomb, player LOS 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 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. Hypergolic - A hypergolic propellant combination used in a rocket engine is one whose components spontaneously ignite when they come into contact with each other.