mods ejected from Bayesian statistics can't duplicate

the power up boss moves faster, has less health,
  it will eject one of your mods after a collision
  and two health power ups

mod ammonium nitrate: increase explosion damage and area by 25%
  also other explosion mods have been rebalanced (damage buffed, but self damage is also higher)

field: wormhole - teleport around, bullets teleport too, blocks and power ups get sucked in
  mobs don't do much in worm hole yet, but that is coming with future mods
This commit is contained in:
landgreen
2020-10-17 17:29:44 -07:00
parent 858fa5fb24
commit 4187645757
11 changed files with 434 additions and 118 deletions

View File

@@ -165,12 +165,13 @@ const b = {
} }
}, },
explosion(where, radius) { // typically explode is used for some bullets with .onEnd explosion(where, radius) { // typically explode is used for some bullets with .onEnd
radius *= mod.explosiveRadius
let dist, sub, knock; let dist, sub, knock;
let dmg = radius * 0.013; let dmg = radius * 0.013;
if (mod.isExplosionHarm) radius *= 1.43 // sqrt(2)radius for 2x more area if (mod.isExplosionHarm) radius *= 1.8 // 1/sqrt(2) radius -> area
if (mod.isSmallExplosion) { if (mod.isSmallExplosion) {
radius *= 0.5 radius *= 0.8
dmg *= 1.5 dmg *= 1.6
} }
game.drawList.push({ //add dmg to draw queue game.drawList.push({ //add dmg to draw queue
@@ -197,7 +198,7 @@ const b = {
if (dist < radius) { if (dist < radius) {
if (mod.isImmuneExplosion) { if (mod.isImmuneExplosion) {
const mitigate = Math.min(1, Math.max(1 - mech.energy * 0.6, 0)) const mitigate = Math.min(1, Math.max(1 - mech.energy * 0.7, 0))
mech.damage(mitigate * radius * (mod.isExplosionHarm ? 0.0004 : 0.0001)); mech.damage(mitigate * radius * (mod.isExplosionHarm ? 0.0004 : 0.0001));
} else { } else {
mech.damage(radius * (mod.isExplosionHarm ? 0.0004 : 0.0001)); mech.damage(radius * (mod.isExplosionHarm ? 0.0004 : 0.0001));
@@ -800,7 +801,6 @@ const b = {
lockedOn: null, lockedOn: null,
isFollowMouse: true, isFollowMouse: true,
onDmg(who) { onDmg(who) {
console.log(who.alive)
mobs.statusSlow(who, 60) mobs.statusSlow(who, 60)
this.endCycle = game.cycle this.endCycle = game.cycle
if (mod.isHeavyWater) mobs.statusDoT(who, 0.15, 300) if (mod.isHeavyWater) mobs.statusDoT(who, 0.15, 300)

View File

@@ -85,16 +85,6 @@ function collisionChecks(event) {
// if (obj.onWallHit) obj.onWallHit(); // if (obj.onWallHit) obj.onWallHit();
// } // }
//body + player collision
// if (game.isBodyDamage) {
// if (pairs[i].bodyA === playerBody || pairs[i].bodyA === playerHead) {
// collidePlayer(pairs[i].bodyB)
// } else if (pairs[i].bodyB === playerBody || pairs[i].bodyB === playerHead) {
// collidePlayer(pairs[i].bodyA)
// }
// }
// function collidePlayer(obj) { // function collidePlayer(obj) {
// //player dmg from hitting a body // //player dmg from hitting a body
// if (obj.classType === "body" && obj.speed > 10 && mech.immuneCycle < mech.cycle) { // if (obj.classType === "body" && obj.speed > 10 && mech.immuneCycle < mech.cycle) {
@@ -145,22 +135,8 @@ function collisionChecks(event) {
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 (mod.isPiezo) mech.energy = mech.maxEnergy; if (mod.isPiezo) mech.energy = mech.maxEnergy;
mech.damage(dmg); mech.damage(dmg);
if (mod.isBayesian) { if (mod.isBayesian) powerUps.ejectMod()
const have = [] //find which mods you have
for (let i = 0; i < mod.mods.length; i++) {
if (mod.mods[i].count > 0) have.push(i)
}
const choose = have[Math.floor(Math.random() * have.length)]
game.makeTextLog(`<div class='circle mod'></div> &nbsp; <strong>${mod.mods[choose].name}</strong> ejected by Bayesian statistics`, 600) //message about what mod was lost
for (let i = 0; i < mod.mods[choose].count; i++) powerUps.spawn(mech.pos.x, mech.pos.y, "mod");
mod.mods[choose].remove(); // remove a random mod form the list of mods you have
mod.mods[choose].count = 0;
mod.mods[choose].isLost = true;
game.updateModHUD();
mech.fieldCDcycle = mech.cycle + 30; //disable field so you can't pick up the ejected mod
}
if (mob[k].onHit) mob[k].onHit(k); if (mob[k].onHit) mob[k].onHit(k);
//extra kick between player and mob //this section would be better with forces but they don't work... //extra kick between player and mob //this section would be better with forces but they don't work...
let angle = Math.atan2(player.position.y - mob[k].position.y, player.position.x - mob[k].position.x); let angle = Math.atan2(player.position.y - mob[k].position.y, player.position.x - mob[k].position.x);
Matter.Body.setVelocity(player, { Matter.Body.setVelocity(player, {

View File

@@ -126,7 +126,6 @@ const game = {
lastTimeStamp: 0, //tracks time stamps for measuring delta lastTimeStamp: 0, //tracks time stamps for measuring delta
delta: 1000 / 60, //speed of game engine //looks like it has to be 16 to match player input delta: 1000 / 60, //speed of game engine //looks like it has to be 16 to match player input
buttonCD: 0, buttonCD: 0,
isBodyDamage: true,
levelsCleared: 0, levelsCleared: 0,
difficultyMode: 1, difficultyMode: 1,
isEasyMode: false, isEasyMode: false,
@@ -472,6 +471,7 @@ const game = {
mech.maxHealth = 1 mech.maxHealth = 1
mech.maxEnergy = 1 mech.maxEnergy = 1
mech.energy = 1 mech.energy = 1
mech.hole.isOn = false
game.paused = false; game.paused = false;
engine.timing.timeScale = 1; engine.timing.timeScale = 1;
game.fpsCap = game.fpsCapDefault; game.fpsCap = game.fpsCapDefault;
@@ -559,7 +559,7 @@ const game = {
if (game.isCommunityMaps) { if (game.isCommunityMaps) {
level.levels.push("stronghold"); level.levels.push("stronghold");
level.levels.push("basement"); level.levels.push("basement");
level.levels.push("newLevel"); level.levels.push("detours");
level.levels.push("house"); level.levels.push("house");
} }
level.levels = shuffle(level.levels); //shuffles order of maps level.levels = shuffle(level.levels); //shuffles order of maps
@@ -607,6 +607,7 @@ const game = {
mech.fireCDcycle = 0 mech.fireCDcycle = 0
mech.drop(); mech.drop();
mech.hole.isOn = false;
level.fill = []; level.fill = [];
level.fillBG = []; level.fillBG = [];
level.zones = []; level.zones = [];

View File

@@ -871,7 +871,13 @@ document.body.addEventListener("wheel", (e) => {
//********************************************************************** //**********************************************************************
let localSettings = JSON.parse(localStorage.getItem("localSettings")); let localSettings = JSON.parse(localStorage.getItem("localSettings"));
if (localSettings) { if (localSettings) {
if (localSettings.key) {
input.key = localSettings.key input.key = localSettings.key
} else {
input.setDefault()
}
game.isCommunityMaps = localSettings.isCommunityMaps game.isCommunityMaps = localSettings.isCommunityMaps
document.getElementById("community-maps").checked = localSettings.isCommunityMaps document.getElementById("community-maps").checked = localSettings.isCommunityMaps
game.difficultyMode = localSettings.difficultyMode game.difficultyMode = localSettings.difficultyMode
@@ -883,15 +889,15 @@ if (localSettings) {
} }
document.getElementById("fps-select").value = localSettings.fpsCapDefault document.getElementById("fps-select").value = localSettings.fpsCapDefault
} else { } else {
input.setDefault()
localSettings = { localSettings = {
isCommunityMaps: false, isCommunityMaps: false,
difficultyMode: '1', difficultyMode: '1',
fpsCapDefault: 'max', fpsCapDefault: 'max',
runCount: 0, runCount: 0,
levelsClearedLastGame: 0, levelsClearedLastGame: 0,
key: input.key key: undefined
}; };
input.setDefault()
localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
document.getElementById("community-maps").checked = localSettings.isCommunityMaps document.getElementById("community-maps").checked = localSettings.isCommunityMaps
game.isCommunityMaps = localSettings.isCommunityMaps game.isCommunityMaps = localSettings.isCommunityMaps

View File

@@ -15,7 +15,7 @@ const level = {
// game.zoomScale = 1000; // game.zoomScale = 1000;
// game.setZoom(); // game.setZoom();
// mech.isCloak = true; // mech.isCloak = true;
// mech.setField("perfect diamagnetism") mech.setField("wormhole")
// b.giveGuns("nail gun") // b.giveGuns("nail gun")
// for (let i = 0; i < 10; i++) { // for (let i = 0; i < 10; i++) {
// mod.giveMod("laser-bot"); // mod.giveMod("laser-bot");
@@ -37,7 +37,7 @@ const level = {
// level.office(); // level.office();
// level.bosses(); //only fighting, very simple map // level.bosses(); //only fighting, very simple map
// level.house() //fan level // level.house() //fan level
// level.newLevel() //fan level // level.detours() //fan level
// level.basement(); //fan level // level.basement(); //fan level
// level.stronghold() //fan level // level.stronghold() //fan level
} else { } else {
@@ -141,7 +141,7 @@ const level = {
spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 100); //exit bump spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 100); //exit bump
// spawn.boost(1500, 0, 900); // spawn.boost(1500, 0, 900);
spawn.starter(1600, -500) // spawn.starter(1600, -500)
// spawn.bomberBoss(2900, -500) // spawn.bomberBoss(2900, -500)
// spawn.launcherBoss(1200, -500) // spawn.launcherBoss(1200, -500)
// spawn.laserTargetingBoss(1600, -400) // spawn.laserTargetingBoss(1600, -400)
@@ -151,7 +151,7 @@ const level = {
// spawn.sniper(1800, -120) // spawn.sniper(1800, -120)
// spawn.sniper(2200, -120) // spawn.sniper(2200, -120)
// spawn.cellBossCulture(1600, -500) // spawn.cellBossCulture(1600, -500)
// spawn.powerUpBoss(1600, -500) spawn.powerUpBoss(1600, -500)
// spawn.shield(mob[mob.length - 1], 1200, -500, 1); // spawn.shield(mob[mob.length - 1], 1200, -500, 1);
// spawn.nodeBoss(1200, -500, "launcher") // spawn.nodeBoss(1200, -500, "launcher")
@@ -2821,7 +2821,7 @@ const level = {
powerUps.spawn(3010, 1630, "mod"); powerUps.spawn(3010, 1630, "mod");
powerUps.spawn(3100, 1630, "heal"); powerUps.spawn(3100, 1630, "heal");
}, },
newLevel() { detours() {
level.setPosToSpawn(0, 0); //lower start level.setPosToSpawn(0, 0); //lower start
level.exit.y = 150; level.exit.y = 150;
spawn.mapRect(level.enter.x, 45, 100, 20); spawn.mapRect(level.enter.x, 45, 100, 20);
@@ -4365,7 +4365,7 @@ const level = {
} }
} }
} }
if (body.length) { // if (body.length) {
for (let i = 0, len = body.length; i < len; i++) { for (let i = 0, len = body.length; i < len; i++) {
if (body[i] !== mech.holdingTarget) { if (body[i] !== mech.holdingTarget) {
// body[i].bounds.max.x - body[i].bounds.min.x < 100 && body[i].bounds.max.y - body[i].bounds.min.y < 100 // body[i].bounds.max.x - body[i].bounds.min.x < 100 && body[i].bounds.max.y - body[i].bounds.min.y < 100
@@ -4391,7 +4391,7 @@ const level = {
} }
} }
} }
} // }
//remove block if touching //remove block if touching
// if (body.length) { // if (body.length) {

View File

@@ -403,8 +403,24 @@ const mod = {
} }
}, },
{ {
name: "trinitrotoluene", name: "ammonium nitrate",
description: "increase <strong class='color-e'>explosive</strong> <strong class='color-d'>damage</strong> by <strong>50%</strong><br>decrease <strong class='color-e'>explosive</strong> <strong>area</strong> by <strong>71%</strong>", description: "increase <strong class='color-e'>explosive</strong> <strong class='color-d'>damage</strong> by <strong>20%</strong><br>increase <strong class='color-e'>explosive</strong> <strong>radius</strong> by <strong>20%</strong>",
maxCount: 9,
count: 0,
allowed() {
return mod.haveGunCheck("missiles") || mod.haveGunCheck("flak") || mod.haveGunCheck("grenades") || mod.haveGunCheck("vacuum bomb") || mod.haveGunCheck("pulse") || mod.isMissileField || mod.boomBotCount > 1;
},
requires: "an explosive damage source",
effect: () => {
mod.explosiveRadius += 0.2;
},
remove() {
mod.explosiveRadius = 1;
}
},
{
name: "nitroglycerin",
description: "increase <strong class='color-e'>explosive</strong> <strong class='color-d'>damage</strong> by <strong>60%</strong><br>decrease <strong class='color-e'>explosive</strong> <strong>radius</strong> by <strong>20%</strong>",
maxCount: 1, maxCount: 1,
count: 0, count: 0,
allowed() { allowed() {
@@ -419,8 +435,8 @@ const mod = {
} }
}, },
{ {
name: "ammonium nitrate", name: "acetone peroxide",
description: "increase <strong class='color-e'>explosive</strong> <strong>area</strong> by <strong>100%</strong>, but<br>you take <strong>400%</strong> more <strong class='color-harm'>harm</strong> from <strong class='color-e'>explosions</strong>", description: "increase <strong class='color-e'>explosive</strong> <strong>radius</strong> by <strong>80%</strong>, but<br>you take <strong>400%</strong> more <strong class='color-harm'>harm</strong> from <strong class='color-e'>explosions</strong>",
maxCount: 1, maxCount: 1,
count: 0, count: 0,
allowed() { allowed() {
@@ -437,7 +453,7 @@ const mod = {
{ {
name: "electric reactive armor", name: "electric reactive armor",
// description: "<strong class='color-e'>explosions</strong> do no <strong class='color-harm'>harm</strong><br> while your <strong class='color-f'>energy</strong> is above <strong>98%</strong>", // description: "<strong class='color-e'>explosions</strong> do no <strong class='color-harm'>harm</strong><br> while your <strong class='color-f'>energy</strong> is above <strong>98%</strong>",
description: "<strong class='color-harm'>harm</strong> from <strong class='color-e'>explosions</strong> is passively reduced<br>by <strong>6%</strong> for every <strong>10</strong> stored <strong class='color-f'>energy</strong>", description: "<strong class='color-harm'>harm</strong> from <strong class='color-e'>explosions</strong> is passively reduced<br>by <strong>7%</strong> for every <strong>10</strong> stored <strong class='color-f'>energy</strong>",
maxCount: 1, maxCount: 1,
count: 0, count: 0,
allowed() { allowed() {
@@ -1192,7 +1208,7 @@ const mod = {
}, },
{ {
name: "Bayesian statistics", name: "Bayesian statistics",
description: "<strong>17%</strong> chance to <strong>duplicate</strong> spawned <strong>power ups</strong><br>after a <strong>collision</strong>, <strong>eject</strong> one of your <strong class='color-m'>mods</strong>", description: "<strong>20%</strong> chance to <strong>duplicate</strong> spawned <strong>power ups</strong><br>after a <strong>collision</strong>, <strong>eject</strong> one of your <strong class='color-m'>mods</strong>",
maxCount: 1, maxCount: 1,
count: 0, count: 0,
allowed() { allowed() {
@@ -1201,13 +1217,13 @@ const mod = {
requires: "", requires: "",
effect: () => { effect: () => {
mod.isBayesian = true mod.isBayesian = true
mod.duplicateChance += 0.17 mod.duplicateChance += 0.2
game.draw.powerUp = game.draw.powerUpBonus //change power up draw game.draw.powerUp = game.draw.powerUpBonus //change power up draw
}, },
remove() { remove() {
if (mod.isBayesian) { if (mod.isBayesian) {
mod.duplicateChance -= 0.17 mod.duplicateChance -= 0.2
if (mod.duplicateChance < 0) mod.duplicateChance = 0 if (mod.duplicateChance < 0) mod.duplicateChance = 0
} }
mod.isBayesian = false mod.isBayesian = false
@@ -1226,12 +1242,12 @@ const mod = {
effect() { effect() {
mod.duplicateChance += 0.08 mod.duplicateChance += 0.08
game.draw.powerUp = game.draw.powerUpBonus //change power up draw game.draw.powerUp = game.draw.powerUpBonus //change power up draw
this.description = `<strong>8%</strong> chance to <strong>duplicate</strong> spawned <strong>power ups</strong><br><em>chance to duplicate = ${mod.duplicateChance}</em>` // this.description = `<strong>8%</strong> chance to <strong>duplicate</strong> spawned <strong>power ups</strong><br><em>chance to duplicate = ${mod.duplicateChance}</em>`
}, },
remove() { remove() {
mod.duplicateChance -= 0.08 * this.count mod.duplicateChance -= 0.08 * this.count
if (mod.duplicateChance === 0) game.draw.powerUp = game.draw.powerUpNormal if (mod.duplicateChance === 0) game.draw.powerUp = game.draw.powerUpNormal
this.description = `<strong>8%</strong> chance to <strong>duplicate</strong> spawned <strong>power ups</strong><br><em>chance to duplicate = ${mod.duplicateChance}</em>` // this.description = `<strong>8%</strong> chance to <strong>duplicate</strong> spawned <strong>power ups</strong><br><em>chance to duplicate = ${mod.duplicateChance}</em>`
} }
}, },
{ {
@@ -1604,7 +1620,7 @@ const mod = {
allowed() { allowed() {
return mod.haveGunCheck("nail gun") && mod.nailFireRate && !mod.isIceCrystals return mod.haveGunCheck("nail gun") && mod.nailFireRate && !mod.isIceCrystals
}, },
requires: "nail gun", requires: "nail gun and pneumatic actuator",
effect() { effect() {
mod.nailInstantFireRate = true mod.nailInstantFireRate = true
}, },
@@ -3023,5 +3039,6 @@ const mod = {
duplicateChance: null, duplicateChance: null,
beamSplitter: null, beamSplitter: null,
iceEnergy: null, iceEnergy: null,
isPerfectBrake: null isPerfectBrake: null,
explosiveRadius: null
} }

View File

@@ -107,7 +107,6 @@ const mech = {
Sy: 0, //adds a smoothing effect to vertical only Sy: 0, //adds a smoothing effect to vertical only
Vx: 0, Vx: 0,
Vy: 0, Vy: 0,
friction: { friction: {
ground: 0.01, ground: 0.01,
air: 0.0025 air: 0.0025
@@ -222,19 +221,18 @@ const mech = {
}, },
buttonCD_jump: 0, //cool down for player buttons buttonCD_jump: 0, //cool down for player buttons
groundControl() { groundControl() {
//check for crouch or jump
if (mech.crouch) { if (mech.crouch) {
if (!(input.down) && mech.checkHeadClear() && mech.hardLandCD < mech.cycle) mech.undoCrouch(); if (!(input.down) && mech.checkHeadClear() && mech.hardLandCD < mech.cycle) mech.undoCrouch();
} else if (input.down || mech.hardLandCD > mech.cycle) { } else if (input.down || mech.hardLandCD > mech.cycle) {
mech.doCrouch(); //on ground && not crouched and pressing s or down mech.doCrouch(); //on ground && not crouched and pressing s or down
} else if ((input.up) && mech.buttonCD_jump + 20 < mech.cycle && mech.yOffWhen.stand > 23) { } else if ((input.up) && mech.buttonCD_jump + 20 < mech.cycle && mech.yOffWhen.stand > 23) {
mech.buttonCD_jump = mech.cycle; //can't jump again until 20 cycles pass mech.buttonCD_jump = mech.cycle; //can't jump again until 20 cycles pass
//apply a fraction of the jump force to the body the player is jumping off of //apply a fraction of the jump force to the body the player is jumping off of
Matter.Body.applyForce(mech.standingOn, mech.pos, { Matter.Body.applyForce(mech.standingOn, mech.pos, {
x: 0, x: 0,
y: mech.jumpForce * 0.12 * Math.min(mech.standingOn.mass, 5) y: mech.jumpForce * 0.12 * Math.min(mech.standingOn.mass, 5)
}); });
player.force.y = -mech.jumpForce; //player jump force player.force.y = -mech.jumpForce; //player jump force
Matter.Body.setVelocity(player, { //zero player y-velocity for consistent jumps Matter.Body.setVelocity(player, { //zero player y-velocity for consistent jumps
x: player.velocity.x, x: player.velocity.x,
@@ -243,9 +241,6 @@ const mech = {
} }
if (input.left) { if (input.left) {
// if (game.mouseDownRight && mech.fieldCDcycle < mech.cycle && !mech.crouch) {
// blink(-1)
// } else {
if (player.velocity.x > -2) { if (player.velocity.x > -2) {
player.force.x -= mech.Fx * 1.5 player.force.x -= mech.Fx * 1.5
} else { } else {
@@ -253,15 +248,11 @@ const mech = {
} }
// } // }
} else if (input.right) { } else if (input.right) {
// if (game.mouseDownRight && mech.fieldCDcycle < mech.cycle && !mech.crouch) {
// blink(1)
// } else {
if (player.velocity.x < 2) { if (player.velocity.x < 2) {
player.force.x += mech.Fx * 1.5 player.force.x += mech.Fx * 1.5
} else { } else {
player.force.x += mech.Fx player.force.x += mech.Fx
} }
// }
} else { } else {
const stoppingFriction = 0.92; const stoppingFriction = 0.92;
Matter.Body.setVelocity(player, { Matter.Body.setVelocity(player, {
@@ -728,6 +719,18 @@ const mech = {
fieldFire: false, fieldFire: false,
fieldHarmReduction: 1, fieldHarmReduction: 1,
holdingMassScale: 0, holdingMassScale: 0,
hole: {
isOn: false,
isReady: true,
pos1: {
x: 0,
y: 0
},
pos2: {
x: 0,
y: 0
},
},
fieldArc: 0, fieldArc: 0,
fieldThreshold: 0, fieldThreshold: 0,
calculateFieldThreshold() { calculateFieldThreshold() {
@@ -739,7 +742,6 @@ const mech = {
mech.fieldMeterColor = "#0cf" mech.fieldMeterColor = "#0cf"
mech.fieldShieldingScale = 1; mech.fieldShieldingScale = 1;
mech.fieldBlockCD = 10; mech.fieldBlockCD = 10;
game.isBodyDamage = true;
mech.fieldHarmReduction = 1; mech.fieldHarmReduction = 1;
mech.fieldDamage = 1 mech.fieldDamage = 1
mech.grabPowerUpRange2 = 156000; mech.grabPowerUpRange2 = 156000;
@@ -757,6 +759,18 @@ const mech = {
mech.isBodiesAsleep = true; mech.isBodiesAsleep = true;
mech.wakeCheck(); mech.wakeCheck();
mech.setMaxEnergy(); mech.setMaxEnergy();
mech.hole = {
isOn: false,
isReady: true,
pos1: {
x: 0,
y: 0
},
pos2: {
x: 0,
y: 0
},
}
}, },
setMaxEnergy() { setMaxEnergy() {
mech.maxEnergy = 1 + mod.bonusEnergy + mod.healMaxEnergyBonus mech.maxEnergy = 1 + mod.bonusEnergy + mod.healMaxEnergyBonus
@@ -996,8 +1010,8 @@ const mech = {
if (dist2 < 5000 && !game.isChoosing) { //use power up if it is close enough if (dist2 < 5000 && !game.isChoosing) { //use power up if it is close enough
powerUps.onPickUp(mech.pos); powerUps.onPickUp(mech.pos);
Matter.Body.setVelocity(player, { //player knock back, after grabbing power up Matter.Body.setVelocity(player, { //player knock back, after grabbing power up
x: player.velocity.x + ((powerUp[i].velocity.x * powerUp[i].mass) / player.mass) * 0.3, x: player.velocity.x + powerUp[i].velocity.x / player.mass * 5,
y: player.velocity.y + ((powerUp[i].velocity.y * powerUp[i].mass) / player.mass) * 0.3 y: player.velocity.y + powerUp[i].velocity.y / player.mass * 5
}); });
powerUp[i].effect(); powerUp[i].effect();
Matter.World.remove(engine.world, powerUp[i]); Matter.World.remove(engine.world, powerUp[i]);
@@ -1544,7 +1558,7 @@ const mech = {
}, },
{ {
name: "plasma torch", name: "plasma torch",
description: "use <strong class='color-f'>energy</strong> to emit short range <strong class='color-plasma'>plasma</strong><br><strong class='color-d'>damages</strong> mobs<br><strong>pushes</strong> mobs and blocks away", description: "use <strong class='color-f'>energy</strong> to emit short range <strong class='color-plasma'>plasma</strong><br><strong class='color-d'>damages</strong> and <strong>pushes</strong> mobs away",
effect() { effect() {
mech.fieldMeterColor = "#f0f" mech.fieldMeterColor = "#f0f"
mech.hold = function () { mech.hold = function () {
@@ -2069,7 +2083,6 @@ const mech = {
description: "use <strong class='color-f'>energy</strong> to push <strong>blocks</strong> with your mouse<br>field <strong>radius</strong> decreases out of <strong>line of sight</strong>", description: "use <strong class='color-f'>energy</strong> to push <strong>blocks</strong> with your mouse<br>field <strong>radius</strong> decreases out of <strong>line of sight</strong>",
effect: () => { effect: () => {
game.replaceTextLog = true; //allow text over write game.replaceTextLog = true; //allow text over write
game.isBodyDamage = false;
mech.fieldPhase = 0; mech.fieldPhase = 0;
mech.fieldPosition = { mech.fieldPosition = {
x: game.mouseInGame.x, x: game.mouseInGame.x,
@@ -2225,5 +2238,220 @@ const mech = {
} }
} }
}, },
{
name: "wormhole",
description: "use <strong class='color-f'>energy</strong> to <strong>tunnel</strong> through a <strong class='color-worm'>wormhole</strong><br>bullets may also traverse the <strong class='color-worm'>wormholes</strong><br>blocks and power ups can't exit it",
effect: () => {
game.replaceTextLog = true; //allow text over write
mech.drop();
// mech.hole = { //this is reset with each new field, but I'm leaving it here for reference
// isOn: false,
// isReady: true,
// pos1: {
// x: 0,
// y: 0
// },
// pos2: {
// x: 0,
// y: 0
// },
// }
mech.hold = function () {
if (mech.hole.isOn) {
// draw holes
mech.fieldRange = 0.97 * mech.fieldRange + 0.03 * (50 + 10 * Math.sin(game.cycle * 0.025))
//draw bezier curves between the portals
const semiMajorAxis = mech.fieldRange + 30
const sub = Vector.sub(mech.hole.pos1, mech.hole.pos2)
const unit = Vector.perp(Vector.normalise(sub))
const edge1a = Vector.add(Vector.mult(unit, semiMajorAxis), mech.hole.pos1)
const edge1b = Vector.add(Vector.mult(unit, -semiMajorAxis), mech.hole.pos1)
const edge2a = Vector.add(Vector.mult(unit, semiMajorAxis), mech.hole.pos2)
const edge2b = Vector.add(Vector.mult(unit, -semiMajorAxis), mech.hole.pos2)
const opacity = 200 / mech.fieldRange / mech.fieldRange
ctx.beginPath();
ctx.moveTo(edge1a.x, edge1a.y)
ctx.bezierCurveTo(mech.hole.pos1.x, mech.hole.pos1.y, mech.hole.pos2.x, mech.hole.pos2.y, edge2a.x, edge2a.y);
ctx.lineTo(edge2b.x, edge2b.y)
ctx.bezierCurveTo(mech.hole.pos2.x, mech.hole.pos2.y, mech.hole.pos1.x, mech.hole.pos1.y, edge1b.x, edge1b.y);
ctx.fillStyle = `rgba(255,255,255,${200 / mech.fieldRange / mech.fieldRange})` //"rgba(0,0,0,0.1)"
ctx.fill();
const angle = Math.atan2(sub.y, sub.x)
ctx.beginPath();
ctx.ellipse(mech.hole.pos1.x, mech.hole.pos1.y, mech.fieldRange, semiMajorAxis, angle, 0, 2 * Math.PI)
ctx.ellipse(mech.hole.pos2.x, mech.hole.pos2.y, mech.fieldRange, semiMajorAxis, angle, 0, 2 * Math.PI)
ctx.fillStyle = `rgba(255,255,255,${32 / mech.fieldRange})`
ctx.fill();
//suck power ups
for (let i = 0, len = powerUp.length; i < len; ++i) {
//which hole is closer
const dxP1 = mech.hole.pos1.x - powerUp[i].position.x;
const dyP1 = mech.hole.pos1.y - powerUp[i].position.y;
const dxP2 = mech.hole.pos2.x - powerUp[i].position.x;
const dyP2 = mech.hole.pos2.y - powerUp[i].position.y;
let dxP, dyP, dist2
if (dxP1 * dxP1 + dyP1 * dyP1 < dxP2 * dxP2 + dyP2 * dyP2) {
dxP = dxP1
dyP = dyP1
} else {
dxP = dxP2
dyP = dyP2
}
dist2 = dxP * dxP + dyP * dyP;
if (dist2 < 600000 && !(mech.health === mech.maxHealth && powerUp[i].name === "heal")) {
powerUp[i].force.x += 4 * (dxP / dist2) * powerUp[i].mass; // float towards hole
powerUp[i].force.y += 4 * (dyP / dist2) * powerUp[i].mass - powerUp[i].mass * game.g; //negate gravity
Matter.Body.setVelocity(powerUp[i], { //extra friction
x: powerUp[i].velocity.x * 0.05,
y: powerUp[i].velocity.y * 0.05
});
if (dist2 < 1000 && !game.isChoosing) { //use power up if it is close enough
mech.fieldRange *= 0.8
powerUps.onPickUp(powerUp[i].position);
powerUp[i].effect();
Matter.World.remove(engine.world, powerUp[i]);
powerUp.splice(i, 1);
break; //because the array order is messed up after splice
}
}
}
//teleport bullets
for (let i = 0, len = bullet.length; i < len; ++i) { //teleport bullets from hole1 to hole2
if (!bullet[i].botType && !bullet[i].isInHole) { //don't teleport bots
if (Vector.magnitude(Vector.sub(mech.hole.pos1, bullet[i].position)) < mech.fieldRange) { //find if bullet is touching hole1
Matter.Body.setPosition(bullet[i], Vector.add(mech.hole.pos2, Vector.sub(mech.hole.pos1, bullet[i].position)));
mech.fieldRange += 5
bullet[i].isInHole = true
} else if (Vector.magnitude(Vector.sub(mech.hole.pos2, bullet[i].position)) < mech.fieldRange) { //find if bullet is touching hole1
Matter.Body.setPosition(bullet[i], Vector.add(mech.hole.pos1, Vector.sub(mech.hole.pos2, bullet[i].position)));
mech.fieldRange += 5
bullet[i].isInHole = true
}
}
}
//suck and shrink blocks
const suckRange = 500
const shrinkRange = 100
const shrinkScale = 0.97;
const slowScale = 0.9
for (let i = 0, len = body.length; i < len; i++) {
if (!body[i].isNotHoldable) {
const dist1 = Vector.magnitude(Vector.sub(mech.hole.pos1, body[i].position))
const dist2 = Vector.magnitude(Vector.sub(mech.hole.pos2, body[i].position))
if (dist1 < dist2) {
if (dist1 < suckRange) {
const pull = Vector.mult(Vector.normalise(Vector.sub(mech.hole.pos1, body[i].position)), 1)
const slow = Vector.mult(body[i].velocity, slowScale)
Matter.Body.setVelocity(body[i], Vector.add(slow, pull));
//shrink
if (Vector.magnitude(Vector.sub(mech.hole.pos1, body[i].position)) < shrinkRange) {
Matter.Body.scale(body[i], shrinkScale, shrinkScale);
if (body[i].mass < 0.05) {
Matter.World.remove(engine.world, body[i]);
body.splice(i, 1);
mech.fieldRange *= 0.8
break
}
}
}
} else if (dist2 < suckRange) {
const pull = Vector.mult(Vector.normalise(Vector.sub(mech.hole.pos2, body[i].position)), 1)
const slow = Vector.mult(body[i].velocity, slowScale)
Matter.Body.setVelocity(body[i], Vector.add(slow, pull));
//shrink
if (Vector.magnitude(Vector.sub(mech.hole.pos2, body[i].position)) < shrinkRange) {
Matter.Body.scale(body[i], shrinkScale, shrinkScale);
if (body[i].mass < 0.05) {
Matter.World.remove(engine.world, body[i]);
body.splice(i, 1);
mech.fieldRange *= 0.8
break
}
}
}
}
}
//mobs get sucked in
for (let i = 0, len = mob.length; i < len; i++) {
if (!mob[i].shield && !mob[i].isShielded) {
if (Vector.magnitude(Vector.sub(mech.hole.pos1, mob[i].position)) < suckRange) {
const pull = Vector.mult(Vector.normalise(Vector.sub(mech.hole.pos1, mob[i].position)), 0.05)
const slow = Vector.mult(mob[i].velocity, 0.99)
Matter.Body.setVelocity(mob[i], Vector.add(slow, pull));
}
if (Vector.magnitude(Vector.sub(mech.hole.pos2, mob[i].position)) < suckRange) {
const pull = Vector.mult(Vector.normalise(Vector.sub(mech.hole.pos2, mob[i].position)), 0.05)
const slow = Vector.mult(mob[i].velocity, 0.99)
Matter.Body.setVelocity(mob[i], Vector.add(slow, pull));
}
}
}
}
if (mech.isHolding) {
mech.drawHold(mech.holdingTarget);
mech.holding();
mech.throwBlock();
} else if ((input.field && mech.fieldCDcycle < mech.cycle)) { //not hold but field button is pressed
// Matter.Query.ray(map, jumpSensor.position, game.mouseInGame).length === 0 ||
if (
mech.hole.isReady && !mech.holdingTarget &&
(Matter.Query.ray(map, player.position, game.mouseInGame).length === 0 && Matter.Query.ray(map, mech.pos, game.mouseInGame).length === 0)
) {
const sub = Vector.sub(game.mouseInGame, mech.pos)
const mag = Vector.magnitude(sub)
const drain = 0.005 * Math.sqrt(mag)
if (mech.energy > drain && mag > 150) {
mech.energy -= drain
mech.hole.isReady = false;
mech.fieldRange = 0
Matter.Body.setPosition(player, game.mouseInGame);
const velocity = Vector.mult(Vector.normalise(sub), 18)
Matter.Body.setVelocity(player, {
x: velocity.x,
y: velocity.y - 4 //an extra vertical kick so the player hangs in place longer
});
mech.immuneCycle = mech.cycle + 15; //player is immune to collision damage for 30 cycles
// move bots to follow player
for (let i = 0; i < bullet.length; i++) {
if (bullet[i].botType) {
Matter.Body.setPosition(bullet[i], Vector.add(player.position, {
x: 250 * (Math.random() - 0.5),
y: 250 * (Math.random() - 0.5)
}));
Matter.Body.setVelocity(bullet[i], {
x: 0,
y: 0
});
}
}
//set holes
mech.hole.isOn = true;
mech.hole.pos1.x = mech.pos.x
mech.hole.pos1.y = mech.pos.y
mech.hole.pos2.x = player.position.x
mech.hole.pos2.y = player.position.y
}
}
// mech.grabPowerUp();
// mech.lookForPickUp(); can't pick things up with this field
// if (mech.energy > 0.05) { //can't use shield
// mech.drawField();
// mech.pushMobsFacing();
// }
} 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)
mech.hole.isReady = true;
}
mech.drawFieldMeter()
}
}
},
], ],
}; };

View File

@@ -541,6 +541,27 @@ const powerUps = {
powerUps.spawnRandomPowerUp(x, y); powerUps.spawnRandomPowerUp(x, y);
} }
}, },
ejectMod() {
//find which mods you have
const have = []
for (let i = 0; i < mod.mods.length; i++) {
if (mod.mods[i].count > 0) have.push(i)
}
if (have.length) {
const choose = have[Math.floor(Math.random() * have.length)]
game.makeTextLog(`<div class='circle mod'></div> &nbsp; <strong>${mod.mods[choose].name}</strong> ejected by Bayesian statistics`, 600) //message about what mod was lost
for (let i = 0; i < mod.mods[choose].count; i++) {
powerUps.directSpawn(mech.pos.x, mech.pos.y, "mod");
powerUp[powerUp.length - 1].isBonus = true
}
// remove a random mod from the list of mods you have
mod.mods[choose].remove();
mod.mods[choose].count = 0;
mod.mods[choose].isLost = true;
game.updateModHUD();
mech.fieldCDcycle = mech.cycle + 30; //disable field so you can't pick up the ejected mod
}
},
directSpawn(x, y, target, moving = true, mode = null, size = powerUps[target].size()) { directSpawn(x, y, target, moving = true, mode = null, size = powerUps[target].size()) {
let index = powerUp.length; let index = powerUp.length;
target = powerUps[target]; target = powerUps[target];

View File

@@ -231,13 +231,13 @@ const spawn = {
mobs.spawn(x, y, vertices, radius, "transparent"); mobs.spawn(x, y, vertices, radius, "transparent");
let me = mob[mob.length - 1]; let me = mob[mob.length - 1];
me.isBoss = true; me.isBoss = true;
me.frictionAir = 0.025 me.frictionAir = 0.01
me.seeAtDistance2 = 9000000; me.seeAtDistance2 = 9000000;
me.accelMag = 0.0005 * game.accelScale; me.accelMag = 0.00062 * game.accelScale;
Matter.Body.setDensity(me, 0.002); //normal is 0.001 Matter.Body.setDensity(me, 0.001); //normal is 0.001
me.collisionFilter.mask = cat.bullet | cat.player me.collisionFilter.mask = cat.bullet | cat.player
me.memory = Infinity; me.memory = Infinity;
me.seePlayerFreq = 85 + Math.floor(10 * Math.random()) me.seePlayerFreq = 60
me.lockedOn = null; me.lockedOn = null;
if (vertices === 9) { if (vertices === 9) {
@@ -248,7 +248,11 @@ const spawn = {
} else if (!mech.isCloak) { } else if (!mech.isCloak) {
me.foundPlayer(); me.foundPlayer();
} }
me.onHit = function () { //run this function on hitting player
powerUps.ejectMod()
powerUps.spawn(mech.pos.x, mech.pos.y, "heal");
powerUps.spawn(mech.pos.x, mech.pos.y, "heal");
};
me.onDeath = function () { me.onDeath = function () {
this.leaveBody = false; this.leaveBody = false;
this.dropPowerUp = false; this.dropPowerUp = false;
@@ -276,6 +280,55 @@ const spawn = {
this.checkStatus(); this.checkStatus();
}; };
}, },
// powerUpBoss(x, y, vertices = 9, radius = 130) {
// mobs.spawn(x, y, vertices, radius, "transparent");
// let me = mob[mob.length - 1];
// me.isBoss = true;
// me.frictionAir = 0.025
// me.seeAtDistance2 = 9000000;
// me.accelMag = 0.0005 * game.accelScale;
// Matter.Body.setDensity(me, 0.002); //normal is 0.001
// me.collisionFilter.mask = cat.bullet | cat.player
// me.memory = Infinity;
// me.seePlayerFreq = 85 + Math.floor(10 * Math.random())
// me.lockedOn = null;
// if (vertices === 9) {
// //on primary spawn
// powerUps.spawnBossPowerUp(me.position.x, me.position.y)
// powerUps.spawn(me.position.x, me.position.y, "heal");
// powerUps.spawn(me.position.x, me.position.y, "ammo");
// } else if (!mech.isCloak) {
// me.foundPlayer();
// }
// me.onDeath = function () {
// this.leaveBody = false;
// this.dropPowerUp = false;
// if (vertices > 3) spawn.powerUpBoss(this.position.x, this.position.y, vertices - 1)
// for (let i = 0; i < powerUp.length; i++) {
// powerUp[i].collisionFilter.mask = cat.map | cat.powerUp
// }
// };
// me.do = function () {
// this.stroke = `hsl(0,0%,${80+25*Math.sin(game.cycle*0.01)}%)`
// //steal all power ups
// for (let i = 0; i < Math.min(powerUp.length, this.vertices.length); i++) {
// powerUp[i].collisionFilter.mask = 0
// Matter.Body.setPosition(powerUp[i], this.vertices[i])
// Matter.Body.setVelocity(powerUp[i], {
// x: 0,
// y: 0
// })
// }
// this.seePlayerCheckByDistance();
// this.attraction();
// this.checkStatus();
// };
// },
// healer(x, y, radius = 20) { // healer(x, y, radius = 20) {
// mobs.spawn(x, y, 3, radius, "rgba(50,255,200,0.4)"); // mobs.spawn(x, y, 3, radius, "rgba(50,255,200,0.4)");
// let me = mob[mob.length - 1]; // let me = mob[mob.length - 1];
@@ -1654,7 +1707,7 @@ const spawn = {
this.explode(this.mass * 10); this.explode(this.mass * 10);
}; };
me.onDeath = function () { me.onDeath = function () {
if (game.difficulty > 7) { if (game.difficulty > 4) {
spawn.bullet(this.position.x, this.position.y, this.radius / 3, 5); spawn.bullet(this.position.x, this.position.y, this.radius / 3, 5);
spawn.bullet(this.position.x, this.position.y, this.radius / 3, 5); spawn.bullet(this.position.x, this.position.y, this.radius / 3, 5);
spawn.bullet(this.position.x, this.position.y, this.radius / 3, 5); spawn.bullet(this.position.x, this.position.y, this.radius / 3, 5);

View File

@@ -488,9 +488,7 @@ em {
} }
.color-plasma { .color-plasma {
/* opacity: 0.5; */
color: #c0e; color: #c0e;
/* color: #000; */
letter-spacing: 1px; letter-spacing: 1px;
background-color: rgba(132, 0, 255, 0.04); background-color: rgba(132, 0, 255, 0.04);
padding: 2px; padding: 2px;
@@ -498,6 +496,12 @@ em {
letter-spacing: 1px; letter-spacing: 1px;
} }
.color-worm {
color: #fff;
text-shadow: 0px 0px 3px #357;
letter-spacing: 1px;
}
.color-harm { .color-harm {
/* color: */ /* color: */
/* text-shadow: #FC0 1px 0 10px; */ /* text-shadow: #FC0 1px 0 10px; */

View File

@@ -1,32 +1,48 @@
mods ejected from Bayesian statistics can't duplicate
ice IX thermoelectric energy 66% -> 100%, heal 3%->4% the power up boss moves faster, has less health,
it will eject one of your mods after a collision
and two health power ups
new key press detection system mod ammonium nitrate: increase explosion damage and area by 25%
I rewrote some fundamental systems so there may be some bugs also other explosion mods have been rebalanced (damage buffed, but self damage is also higher)
testing mode death is now shift X (was x+z)
you can now change your keys with the controls settings field: wormhole - teleport around, bullets teleport too, blocks and power ups get sucked in
this is probably buggy too mobs don't do much in worm hole yet, but that is coming with future mods
************** TODO - n-gon ************** ************** TODO - n-gon **************
laser portal field add an ending to the game
teleport to blocks and map elements in line of sight (like the how the laser works) revamp the boss level, or add a new final level
do damage to mobs in the path of your teleportation final level requires you to kill something, not skip content
go immune to damage for 1 second after teleportation around level 15
after jumping into the portal you can send things back to your old location, like bullets and blocks, and mobs game never ends if you have used cheats
add testing key for spawn boss mob field wormhole
mobs are protected from bullets when stuck in a hole
mobs should destabilize holes, or take damage
store constant info about the holes: unit, angle to save processing
maybe bullets should be able to enter and exit multiple times
or bullets shouldn't get stuck at all?
maybe give bullets an attraction to holes
player: drain energy when near a hole, does damage if no energy
mod: Hawking radiation: do damage, to mobs that get near the end points
this is good because it explains why mobs don't teleport
mod: cosmic string: do damage, like a laser for any mob that passes between the two portals, near the bezier curves
mod: extend immunity cycle after a teleport //mech.immuneCycle = mech.cycle + 15;
mod: reduce energy cost of teleportation
look for mods that could update description text with count and mod.is information look for mods that could update description text with count and mod.is information
can only use variables that change in effect() and remove()
this.description = `<strong>8%</strong> chance to <strong>duplicate</strong> spawned <strong>power ups</strong><br><em>chance to duplicate = ${mod.duplicateChance}</em>` this.description = `<strong>8%</strong> chance to <strong>duplicate</strong> spawned <strong>power ups</strong><br><em>chance to duplicate = ${mod.duplicateChance}</em>`
give the power up boss the ability to eject your mobs if it hits you mod (drones or spores) explode after 10 seconds
mouse event e.which is deprecated mouse event e.which is deprecated
time dilation mod rework brain storm time dilation mod rework (time dilation is cool, but it can feel like a chore)
redistribute effects
take no damage take no damage
can fire can fire
2x move jump fire while field is active 2x move jump fire while field is active
@@ -37,12 +53,6 @@ vacuum bomb applies status effect to mobs that makes blocks attracted to them
mod: take less harm if you are moving fast mod: take less harm if you are moving fast
require squirrel cage rotor require squirrel cage rotor
getting stuck above a mob can immobilize player
just allow player to jump on mobs again?
occurs with Pauli exclusion, and time dilation field immunity - mod time-like world line
add a knock to player mob collisions even while player is immune to damage
keep the knock very small
bug - mine spawned one new mine every second bug - mine spawned one new mine every second
after sticking to the top right corner of a wall after sticking to the top right corner of a wall
notes: had only gun mine, mod mine reclamation, field plasma, notes: had only gun mine, mod mine reclamation, field plasma,