diff --git a/js/bullet.js b/js/bullet.js
index 1656e40..a726528 100644
--- a/js/bullet.js
+++ b/js/bullet.js
@@ -165,12 +165,13 @@ const b = {
}
},
explosion(where, radius) { // typically explode is used for some bullets with .onEnd
+ radius *= mod.explosiveRadius
let dist, sub, knock;
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) {
- radius *= 0.5
- dmg *= 1.5
+ radius *= 0.8
+ dmg *= 1.6
}
game.drawList.push({ //add dmg to draw queue
@@ -197,7 +198,7 @@ const b = {
if (dist < radius) {
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));
} else {
mech.damage(radius * (mod.isExplosionHarm ? 0.0004 : 0.0001));
@@ -800,7 +801,6 @@ const b = {
lockedOn: null,
isFollowMouse: true,
onDmg(who) {
- console.log(who.alive)
mobs.statusSlow(who, 60)
this.endCycle = game.cycle
if (mod.isHeavyWater) mobs.statusDoT(who, 0.15, 300)
diff --git a/js/engine.js b/js/engine.js
index 7e32677..444929e 100644
--- a/js/engine.js
+++ b/js/engine.js
@@ -85,16 +85,6 @@ function collisionChecks(event) {
// 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) {
// //player dmg from hitting a body
// 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
if (mod.isPiezo) mech.energy = mech.maxEnergy;
mech.damage(dmg);
- if (mod.isBayesian) {
- 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(`
${mod.mods[choose].name} 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 (mod.isBayesian) powerUps.ejectMod()
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...
let angle = Math.atan2(player.position.y - mob[k].position.y, player.position.x - mob[k].position.x);
Matter.Body.setVelocity(player, {
diff --git a/js/game.js b/js/game.js
index 4096d25..e8d8e6f 100644
--- a/js/game.js
+++ b/js/game.js
@@ -126,7 +126,6 @@ const game = {
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
buttonCD: 0,
- isBodyDamage: true,
levelsCleared: 0,
difficultyMode: 1,
isEasyMode: false,
@@ -472,6 +471,7 @@ const game = {
mech.maxHealth = 1
mech.maxEnergy = 1
mech.energy = 1
+ mech.hole.isOn = false
game.paused = false;
engine.timing.timeScale = 1;
game.fpsCap = game.fpsCapDefault;
@@ -559,7 +559,7 @@ const game = {
if (game.isCommunityMaps) {
level.levels.push("stronghold");
level.levels.push("basement");
- level.levels.push("newLevel");
+ level.levels.push("detours");
level.levels.push("house");
}
level.levels = shuffle(level.levels); //shuffles order of maps
@@ -607,6 +607,7 @@ const game = {
mech.fireCDcycle = 0
mech.drop();
+ mech.hole.isOn = false;
level.fill = [];
level.fillBG = [];
level.zones = [];
diff --git a/js/index.js b/js/index.js
index e900573..a80d1c6 100644
--- a/js/index.js
+++ b/js/index.js
@@ -871,7 +871,13 @@ document.body.addEventListener("wheel", (e) => {
//**********************************************************************
let localSettings = JSON.parse(localStorage.getItem("localSettings"));
if (localSettings) {
- input.key = localSettings.key
+ if (localSettings.key) {
+ input.key = localSettings.key
+ } else {
+ input.setDefault()
+ }
+
+
game.isCommunityMaps = localSettings.isCommunityMaps
document.getElementById("community-maps").checked = localSettings.isCommunityMaps
game.difficultyMode = localSettings.difficultyMode
@@ -883,15 +889,15 @@ if (localSettings) {
}
document.getElementById("fps-select").value = localSettings.fpsCapDefault
} else {
- input.setDefault()
localSettings = {
isCommunityMaps: false,
difficultyMode: '1',
fpsCapDefault: 'max',
runCount: 0,
levelsClearedLastGame: 0,
- key: input.key
+ key: undefined
};
+ input.setDefault()
localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
document.getElementById("community-maps").checked = localSettings.isCommunityMaps
game.isCommunityMaps = localSettings.isCommunityMaps
diff --git a/js/level.js b/js/level.js
index 8ea014a..c4b3116 100644
--- a/js/level.js
+++ b/js/level.js
@@ -15,7 +15,7 @@ const level = {
// game.zoomScale = 1000;
// game.setZoom();
// mech.isCloak = true;
- // mech.setField("perfect diamagnetism")
+ mech.setField("wormhole")
// b.giveGuns("nail gun")
// for (let i = 0; i < 10; i++) {
// mod.giveMod("laser-bot");
@@ -37,7 +37,7 @@ const level = {
// level.office();
// level.bosses(); //only fighting, very simple map
// level.house() //fan level
- // level.newLevel() //fan level
+ // level.detours() //fan level
// level.basement(); //fan level
// level.stronghold() //fan level
} else {
@@ -141,7 +141,7 @@ const level = {
spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 100); //exit bump
// spawn.boost(1500, 0, 900);
- spawn.starter(1600, -500)
+ // spawn.starter(1600, -500)
// spawn.bomberBoss(2900, -500)
// spawn.launcherBoss(1200, -500)
// spawn.laserTargetingBoss(1600, -400)
@@ -151,7 +151,7 @@ const level = {
// spawn.sniper(1800, -120)
// spawn.sniper(2200, -120)
// spawn.cellBossCulture(1600, -500)
- // spawn.powerUpBoss(1600, -500)
+ spawn.powerUpBoss(1600, -500)
// spawn.shield(mob[mob.length - 1], 1200, -500, 1);
// spawn.nodeBoss(1200, -500, "launcher")
@@ -2821,7 +2821,7 @@ const level = {
powerUps.spawn(3010, 1630, "mod");
powerUps.spawn(3100, 1630, "heal");
},
- newLevel() {
+ detours() {
level.setPosToSpawn(0, 0); //lower start
level.exit.y = 150;
spawn.mapRect(level.enter.x, 45, 100, 20);
@@ -4365,33 +4365,33 @@ const level = {
}
}
}
- if (body.length) {
- for (let i = 0, len = body.length; i < len; i++) {
- 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
- if (Matter.Query.collides(this, [body[i]]).length === 0) {
- if (body[i].isInPortal === this) body[i].isInPortal = null
- } else if (body[i].isInPortal !== this) {
- body[i].isInPortal = this.portalPair
- //teleport
- if (this.portalPair.angle % (Math.PI / 2)) { //if left, right up or down
- Matter.Body.setPosition(body[i], this.portalPair.portal.position);
- } else { //if at some odd angle
- Matter.Body.setPosition(body[i], this.portalPair.position);
- }
- //rotate velocity
- let mag
- if (this.portalPair.angle !== 0 && this.portalPair.angle !== Math.PI) { //portal that fires the player up
- mag = Math.max(10, Math.min(50, body[i].velocity.y * 0.8)) + 11
- } else {
- mag = Math.max(6, Math.min(50, Vector.magnitude(body[i].velocity)))
- }
- let v = Vector.mult(this.portalPair.unit, mag)
- Matter.Body.setVelocity(body[i], v);
+ // if (body.length) {
+ for (let i = 0, len = body.length; i < len; i++) {
+ 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
+ if (Matter.Query.collides(this, [body[i]]).length === 0) {
+ if (body[i].isInPortal === this) body[i].isInPortal = null
+ } else if (body[i].isInPortal !== this) {
+ body[i].isInPortal = this.portalPair
+ //teleport
+ if (this.portalPair.angle % (Math.PI / 2)) { //if left, right up or down
+ Matter.Body.setPosition(body[i], this.portalPair.portal.position);
+ } else { //if at some odd angle
+ Matter.Body.setPosition(body[i], this.portalPair.position);
}
+ //rotate velocity
+ let mag
+ if (this.portalPair.angle !== 0 && this.portalPair.angle !== Math.PI) { //portal that fires the player up
+ mag = Math.max(10, Math.min(50, body[i].velocity.y * 0.8)) + 11
+ } else {
+ mag = Math.max(6, Math.min(50, Vector.magnitude(body[i].velocity)))
+ }
+ let v = Vector.mult(this.portalPair.unit, mag)
+ Matter.Body.setVelocity(body[i], v);
}
}
}
+ // }
//remove block if touching
// if (body.length) {
diff --git a/js/mods.js b/js/mods.js
index 352f4d9..58edd67 100644
--- a/js/mods.js
+++ b/js/mods.js
@@ -403,8 +403,24 @@ const mod = {
}
},
{
- name: "trinitrotoluene",
- description: "increase explosive damage by 50%
decrease explosive area by 71%",
+ name: "ammonium nitrate",
+ description: "increase explosive damage by 20%
increase explosive radius by 20%",
+ 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 explosive damage by 60%
decrease explosive radius by 20%",
maxCount: 1,
count: 0,
allowed() {
@@ -419,8 +435,8 @@ const mod = {
}
},
{
- name: "ammonium nitrate",
- description: "increase explosive area by 100%, but
you take 400% more harm from explosions",
+ name: "acetone peroxide",
+ description: "increase explosive radius by 80%, but
you take 400% more harm from explosions",
maxCount: 1,
count: 0,
allowed() {
@@ -437,7 +453,7 @@ const mod = {
{
name: "electric reactive armor",
// description: "explosions do no harm
while your energy is above 98%",
- description: "harm from explosions is passively reduced
by 6% for every 10 stored energy",
+ description: "harm from explosions is passively reduced
by 7% for every 10 stored energy",
maxCount: 1,
count: 0,
allowed() {
@@ -1192,7 +1208,7 @@ const mod = {
},
{
name: "Bayesian statistics",
- description: "17% chance to duplicate spawned power ups
after a collision, eject one of your mods",
+ description: "20% chance to duplicate spawned power ups
after a collision, eject one of your mods",
maxCount: 1,
count: 0,
allowed() {
@@ -1201,13 +1217,13 @@ const mod = {
requires: "",
effect: () => {
mod.isBayesian = true
- mod.duplicateChance += 0.17
+ mod.duplicateChance += 0.2
game.draw.powerUp = game.draw.powerUpBonus //change power up draw
},
remove() {
if (mod.isBayesian) {
- mod.duplicateChance -= 0.17
+ mod.duplicateChance -= 0.2
if (mod.duplicateChance < 0) mod.duplicateChance = 0
}
mod.isBayesian = false
@@ -1226,12 +1242,12 @@ const mod = {
effect() {
mod.duplicateChance += 0.08
game.draw.powerUp = game.draw.powerUpBonus //change power up draw
- this.description = `8% chance to duplicate spawned power ups
chance to duplicate = ${mod.duplicateChance}`
+ // this.description = `8% chance to duplicate spawned power ups
chance to duplicate = ${mod.duplicateChance}`
},
remove() {
mod.duplicateChance -= 0.08 * this.count
if (mod.duplicateChance === 0) game.draw.powerUp = game.draw.powerUpNormal
- this.description = `8% chance to duplicate spawned power ups
chance to duplicate = ${mod.duplicateChance}`
+ // this.description = `8% chance to duplicate spawned power ups
chance to duplicate = ${mod.duplicateChance}`
}
},
{
@@ -1604,7 +1620,7 @@ const mod = {
allowed() {
return mod.haveGunCheck("nail gun") && mod.nailFireRate && !mod.isIceCrystals
},
- requires: "nail gun",
+ requires: "nail gun and pneumatic actuator",
effect() {
mod.nailInstantFireRate = true
},
@@ -3023,5 +3039,6 @@ const mod = {
duplicateChance: null,
beamSplitter: null,
iceEnergy: null,
- isPerfectBrake: null
+ isPerfectBrake: null,
+ explosiveRadius: null
}
\ No newline at end of file
diff --git a/js/player.js b/js/player.js
index cc13bee..38f9ec4 100644
--- a/js/player.js
+++ b/js/player.js
@@ -107,7 +107,6 @@ const mech = {
Sy: 0, //adds a smoothing effect to vertical only
Vx: 0,
Vy: 0,
-
friction: {
ground: 0.01,
air: 0.0025
@@ -222,19 +221,18 @@ const mech = {
},
buttonCD_jump: 0, //cool down for player buttons
groundControl() {
+ //check for crouch or jump
if (mech.crouch) {
if (!(input.down) && mech.checkHeadClear() && mech.hardLandCD < mech.cycle) mech.undoCrouch();
} else if (input.down || mech.hardLandCD > mech.cycle) {
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) {
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
Matter.Body.applyForce(mech.standingOn, mech.pos, {
x: 0,
y: mech.jumpForce * 0.12 * Math.min(mech.standingOn.mass, 5)
});
-
player.force.y = -mech.jumpForce; //player jump force
Matter.Body.setVelocity(player, { //zero player y-velocity for consistent jumps
x: player.velocity.x,
@@ -243,9 +241,6 @@ const mech = {
}
if (input.left) {
- // if (game.mouseDownRight && mech.fieldCDcycle < mech.cycle && !mech.crouch) {
- // blink(-1)
- // } else {
if (player.velocity.x > -2) {
player.force.x -= mech.Fx * 1.5
} else {
@@ -253,15 +248,11 @@ const mech = {
}
// }
} else if (input.right) {
- // if (game.mouseDownRight && mech.fieldCDcycle < mech.cycle && !mech.crouch) {
- // blink(1)
- // } else {
if (player.velocity.x < 2) {
player.force.x += mech.Fx * 1.5
} else {
player.force.x += mech.Fx
}
- // }
} else {
const stoppingFriction = 0.92;
Matter.Body.setVelocity(player, {
@@ -728,6 +719,18 @@ const mech = {
fieldFire: false,
fieldHarmReduction: 1,
holdingMassScale: 0,
+ hole: {
+ isOn: false,
+ isReady: true,
+ pos1: {
+ x: 0,
+ y: 0
+ },
+ pos2: {
+ x: 0,
+ y: 0
+ },
+ },
fieldArc: 0,
fieldThreshold: 0,
calculateFieldThreshold() {
@@ -739,7 +742,6 @@ const mech = {
mech.fieldMeterColor = "#0cf"
mech.fieldShieldingScale = 1;
mech.fieldBlockCD = 10;
- game.isBodyDamage = true;
mech.fieldHarmReduction = 1;
mech.fieldDamage = 1
mech.grabPowerUpRange2 = 156000;
@@ -757,6 +759,18 @@ const mech = {
mech.isBodiesAsleep = true;
mech.wakeCheck();
mech.setMaxEnergy();
+ mech.hole = {
+ isOn: false,
+ isReady: true,
+ pos1: {
+ x: 0,
+ y: 0
+ },
+ pos2: {
+ x: 0,
+ y: 0
+ },
+ }
},
setMaxEnergy() {
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
powerUps.onPickUp(mech.pos);
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,
- y: player.velocity.y + ((powerUp[i].velocity.y * 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 / player.mass * 5
});
powerUp[i].effect();
Matter.World.remove(engine.world, powerUp[i]);
@@ -1544,7 +1558,7 @@ const mech = {
},
{
name: "plasma torch",
- description: "use energy to emit short range plasma
damages mobs
pushes mobs and blocks away",
+ description: "use energy to emit short range plasma
damages and pushes mobs away",
effect() {
mech.fieldMeterColor = "#f0f"
mech.hold = function () {
@@ -2069,7 +2083,6 @@ const mech = {
description: "use energy to push blocks with your mouse
field radius decreases out of line of sight",
effect: () => {
game.replaceTextLog = true; //allow text over write
- game.isBodyDamage = false;
mech.fieldPhase = 0;
mech.fieldPosition = {
x: game.mouseInGame.x,
@@ -2225,5 +2238,220 @@ const mech = {
}
}
},
+ {
+ name: "wormhole",
+ description: "use energy to tunnel through a wormhole
bullets may also traverse the wormholes
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()
+ }
+ }
+ },
],
};
\ No newline at end of file
diff --git a/js/powerup.js b/js/powerup.js
index e809722..c0afd8f 100644
--- a/js/powerup.js
+++ b/js/powerup.js
@@ -541,6 +541,27 @@ const powerUps = {
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(` ${mod.mods[choose].name} 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()) {
let index = powerUp.length;
target = powerUps[target];
diff --git a/js/spawn.js b/js/spawn.js
index c384444..ce3804c 100644
--- a/js/spawn.js
+++ b/js/spawn.js
@@ -231,13 +231,13 @@ const spawn = {
mobs.spawn(x, y, vertices, radius, "transparent");
let me = mob[mob.length - 1];
me.isBoss = true;
- me.frictionAir = 0.025
+ me.frictionAir = 0.01
me.seeAtDistance2 = 9000000;
- me.accelMag = 0.0005 * game.accelScale;
- Matter.Body.setDensity(me, 0.002); //normal is 0.001
+ me.accelMag = 0.00062 * game.accelScale;
+ Matter.Body.setDensity(me, 0.001); //normal is 0.001
me.collisionFilter.mask = cat.bullet | cat.player
me.memory = Infinity;
- me.seePlayerFreq = 85 + Math.floor(10 * Math.random())
+ me.seePlayerFreq = 60
me.lockedOn = null;
if (vertices === 9) {
@@ -248,7 +248,11 @@ const spawn = {
} else if (!mech.isCloak) {
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 () {
this.leaveBody = false;
this.dropPowerUp = false;
@@ -276,6 +280,55 @@ const spawn = {
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) {
// mobs.spawn(x, y, 3, radius, "rgba(50,255,200,0.4)");
// let me = mob[mob.length - 1];
@@ -1654,7 +1707,7 @@ const spawn = {
this.explode(this.mass * 10);
};
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);
diff --git a/style.css b/style.css
index 4ff1674..86bf1b2 100644
--- a/style.css
+++ b/style.css
@@ -488,9 +488,7 @@ em {
}
.color-plasma {
- /* opacity: 0.5; */
color: #c0e;
- /* color: #000; */
letter-spacing: 1px;
background-color: rgba(132, 0, 255, 0.04);
padding: 2px;
@@ -498,6 +496,12 @@ em {
letter-spacing: 1px;
}
+.color-worm {
+ color: #fff;
+ text-shadow: 0px 0px 3px #357;
+ letter-spacing: 1px;
+}
+
.color-harm {
/* color: */
/* text-shadow: #FC0 1px 0 10px; */
diff --git a/todo.txt b/todo.txt
index 3cb94ef..665eecc 100644
--- a/todo.txt
+++ b/todo.txt
@@ -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
- I rewrote some fundamental systems so there may be some bugs
- testing mode death is now shift X (was x+z)
+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)
-you can now change your keys with the controls settings
- this is probably buggy too
+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
************** TODO - n-gon **************
-laser portal field
- teleport to blocks and map elements in line of sight (like the how the laser works)
- do damage to mobs in the path of your teleportation
- go immune to damage for 1 second after teleportation
- after jumping into the portal you can send things back to your old location, like bullets and blocks, and mobs
+add an ending to the game
+ revamp the boss level, or add a new final level
+ final level requires you to kill something, not skip content
+ around level 15
+ 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
+ can only use variables that change in effect() and remove()
this.description = `8% chance to duplicate spawned power ups
chance to duplicate = ${mod.duplicateChance}`
-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
-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
can fire
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
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
after sticking to the top right corner of a wall
notes: had only gun mine, mod mine reclamation, field plasma,