wormhole
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:
10
js/bullet.js
10
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)
|
||||
|
||||
26
js/engine.js
26
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(`<div class='circle mod'></div> <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 (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, {
|
||||
|
||||
@@ -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 = [];
|
||||
|
||||
12
js/index.js
12
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
|
||||
|
||||
56
js/level.js
56
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) {
|
||||
|
||||
41
js/mods.js
41
js/mods.js
@@ -403,8 +403,24 @@ const mod = {
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "trinitrotoluene",
|
||||
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>",
|
||||
name: "ammonium nitrate",
|
||||
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,
|
||||
count: 0,
|
||||
allowed() {
|
||||
@@ -419,8 +435,8 @@ const mod = {
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "ammonium nitrate",
|
||||
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>",
|
||||
name: "acetone peroxide",
|
||||
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,
|
||||
count: 0,
|
||||
allowed() {
|
||||
@@ -437,7 +453,7 @@ const mod = {
|
||||
{
|
||||
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-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,
|
||||
count: 0,
|
||||
allowed() {
|
||||
@@ -1192,7 +1208,7 @@ const mod = {
|
||||
},
|
||||
{
|
||||
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,
|
||||
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 = `<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() {
|
||||
mod.duplicateChance -= 0.08 * this.count
|
||||
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() {
|
||||
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
|
||||
}
|
||||
258
js/player.js
258
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 <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() {
|
||||
mech.fieldMeterColor = "#f0f"
|
||||
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>",
|
||||
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 <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()
|
||||
}
|
||||
}
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -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(`<div class='circle mod'></div> <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()) {
|
||||
let index = powerUp.length;
|
||||
target = powerUps[target];
|
||||
|
||||
65
js/spawn.js
65
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);
|
||||
|
||||
Reference in New Issue
Block a user