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
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)

View File

@@ -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> &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 (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, {

View File

@@ -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 = [];

View File

@@ -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

View File

@@ -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) {

View File

@@ -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
}

View File

@@ -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()
}
}
},
],
};

View File

@@ -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> &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()) {
let index = powerUp.length;
target = powerUps[target];

View File

@@ -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);