laser boss

added laser boss, getting ready for new map
limit on born rule spawn
some gun balance
Pauli exclusion buff
This commit is contained in:
landgreen
2020-01-24 04:52:23 -08:00
parent 95c09efc5e
commit c7e85dcc02
8 changed files with 192 additions and 65 deletions

View File

@@ -111,7 +111,7 @@ const b = {
},
{
name: "kinetic bombardment", //3
description: "do up to 33% more <strong class='color-d'>damage</strong> at a distance<br><em>increase starts at about 6 steps away</em>",
description: "do up to 33% more <strong class='color-d'>damage</strong> at a distance<br><em>increase maxes out at about 40 steps away</em>",
maxCount: 1,
count: 0,
effect() {
@@ -139,11 +139,11 @@ const b = {
},
{
name: "auto-loading heuristics", //5
description: "your <strong>delay</strong> after firing is +12% <strong>shorter</strong>",
maxCount: 5,
description: "your <strong>delay</strong> after firing is +14% <strong>shorter</strong>",
maxCount: 3,
count: 0,
effect() {
b.modFireRate *= 0.88
b.modFireRate *= 0.86
}
},
{
@@ -239,11 +239,11 @@ const b = {
},
{
name: "Pauli exclusion", //12
description: "unable to <strong>collide</strong> with enemies for +1 second<br>activates after being <strong>harmed</strong> from a collision",
description: "unable to <strong>collide</strong> with enemies for +2 second<br>activates after being <strong>harmed</strong> from a collision",
maxCount: 9,
count: 0,
effect() {
b.modCollisionImmuneCycles += 60;
b.modCollisionImmuneCycles += 120;
mech.collisionImmune = mech.cycle + b.modCollisionImmuneCycles; //player is immune to collision damage for 30 cycles
}
},
@@ -307,7 +307,7 @@ const b = {
},
{
name: "recursive healing", //22
description: "<strong class='color-h'>healing</strong> power ups trigger an extra time.",
description: "<strong class='color-h'>healing</strong> power ups trigger one extra time.",
maxCount: 9,
count: 0,
effect() {
@@ -1191,7 +1191,7 @@ const b = {
name: "super balls", //2
description: "fire <strong>five</strong> balls in a wide arc<br>balls <strong>bounce</strong> with no momentum loss",
ammo: 0,
ammoPack: 5,
ammoPack: 6,
have: false,
isStarterGun: true,
fire() {
@@ -1317,7 +1317,7 @@ const b = {
name: "missiles", //5
description: "fire missiles that accelerate towards enemies<br><strong class='color-e'>explodes</strong> when near target",
ammo: 0,
ammoPack: 3,
ammoPack: 4,
have: false,
isStarterGun: false,
fireCycle: 0,
@@ -1327,7 +1327,7 @@ const b = {
const me = bullet.length;
bullet[me] = Bodies.rectangle(mech.pos.x + 40 * Math.cos(mech.angle), mech.pos.y + 40 * Math.sin(mech.angle) - 3, 30 * b.modBulletSize, 4 * b.modBulletSize, b.fireAttributes(dir));
const thrust = 0.00417 * bullet[me].mass;
b.fireProps(mech.crouch ? 55 : 30, -3 * (0.5 - Math.random()) + (mech.crouch ? 25 : -8), dir, me); //cd , speed
b.fireProps(mech.crouch ? 50 : 25, -3 * (0.5 - Math.random()) + (mech.crouch ? 25 : -8), dir, me); //cd , speed
// bullet[me].collisionFilter.mask = cat.map | cat.body | cat.mobBullet
// Matter.Body.setDensity(bullet[me], 0.01) //doesn't help with reducing explosion knock backs
bullet[me].force.y += 0.0005; //a small push down at first to make it seem like the missile is briefly falling
@@ -1458,7 +1458,7 @@ const b = {
name: "grenades", //7
description: "lob a single bouncy projectile<br><strong class='color-e'>explodes</strong> on contact or after one second",
ammo: 0,
ammoPack: 6,
ammoPack: 7,
have: false,
isStarterGun: false,
fire() {
@@ -1500,7 +1500,7 @@ const b = {
bullet[me].restitution = 0.2;
bullet[me].friction = 0.3;
bullet[me].endCycle = Infinity
bullet[me].explodeRad = 380 + Math.floor(Math.random() * 60);
bullet[me].explodeRad = 400 + Math.floor(Math.random() * 60);
bullet[me].onEnd = function () {
b.explosion(this.position, this.explodeRad); //makes bullet do explosive damage at end
}
@@ -1844,10 +1844,10 @@ const b = {
} else if (mech.fieldMeter > 0.005) { // charging on mouse down
mech.fireCDcycle = Infinity //can't fire until mouse is released
const lastCharge = this.charge
let chargeRate = (mech.crouch) ? 0.965 : 0.985
let chargeRate = (mech.crouch) ? 0.975 : 0.987
chargeRate *= Math.pow(b.modFireRate, 0.04)
this.charge = this.charge * chargeRate + (1 - chargeRate) // this.charge converges to 1
mech.fieldMeter -= (this.charge - lastCharge) * 0.25 //energy drain is proportional to charge gained, but doesn't stop normal mech.fieldRegen
mech.fieldMeter -= (this.charge - lastCharge) * 0.28 //energy drain is proportional to charge gained, but doesn't stop normal mech.fieldRegen
//draw laser targeting
let best;
@@ -1970,7 +1970,7 @@ const b = {
have: false,
isStarterGun: true,
fire() {
const FIELD_DRAIN = 0.002 //laser drains energy as well as bullets
const FIELD_DRAIN = 0.0018 //laser drains energy as well as bullets
const damage = 0.05
if (mech.fieldMeter < FIELD_DRAIN) {
mech.fireCDcycle = mech.cycle + 100; // cool down if out of energy
@@ -2217,7 +2217,7 @@ const b = {
//use energy to explode
const energy = 0.3 * Math.min(mech.fieldMeter, 1.75)
mech.fieldMeter -= energy
if (best.who) b.explosion(path[1], 950 * energy)
if (best.who) b.explosion(path[1], 1000 * energy)
mech.fireCDcycle = mech.cycle + Math.floor(60 * b.modFireRate); // cool down
//draw laser beam

View File

@@ -180,7 +180,7 @@ const game = {
replaceTextLog: true,
// <!-- <path d="M832.41,106.64 V323.55 H651.57 V256.64 c0-82.5,67.5-150,150-150 Z" fill="#789" stroke="none" />
// <path d="M827,112 h30 a140,140,0,0,1,140,140 v68 h-167 z" fill="#7ce" stroke="none" /> -->
SVGleftMouse: '<svg viewBox="750 0 200 765" class="mouse-icon" width="40px" height = "60px" stroke-linecap="round" stroke-linejoin="round" stroke-width="25px" stroke="#000" fill="none"> <path fill="#fff" stroke="none" d="M827,112 h30 a140,140,0,0,1,140,140 v268 a140,140,0,0,1-140,140 h-60 a140,140,0,0,1-140-140v-268 a140,140,0,0,1,140-140h60" /> <path d="M832.41,106.64 V323.55 H651.57 V256.64 c0-82.5,67.5-150,150-150 Z" fill="#456" stroke="none" /> <path fill="none" d="M827,112 h30 a140,140,0,0,1,140,140 v268 a140,140,0,0,1-140,140 h-60 a140,140,0,0,1-140-140v-268 a140,140,0,0,1,140-140h60" /> <path d="M657 317 h 340 h-170 v-207" /> <ellipse fill="#fff" cx="827.57" cy="218.64" rx="29" ry="68" /> </svg>',
SVGleftMouse: '<svg viewBox="750 0 200 765" class="mouse-icon" width="40px" height = "60px" stroke-linecap="round" stroke-linejoin="round" stroke-width="25px" stroke="#000" fill="none"> <path fill="#fff" stroke="none" d="M827,112 h30 a140,140,0,0,1,140,140 v268 a140,140,0,0,1-140,140 h-60 a140,140,0,0,1-140-140v-268 a140,140,0,0,1,140-140h60" /> <path d="M832.41,106.64 V323.55 H651.57 V256.64 c0-82.5,67.5-150,150-150 Z" fill="#149" stroke="none" /> <path fill="none" d="M827,112 h30 a140,140,0,0,1,140,140 v268 a140,140,0,0,1-140,140 h-60 a140,140,0,0,1-140-140v-268 a140,140,0,0,1,140-140h60" /> <path d="M657 317 h 340 h-170 v-207" /> <ellipse fill="#fff" cx="827.57" cy="218.64" rx="29" ry="68" /> </svg>',
SVGrightMouse: '<svg viewBox="750 0 200 765" class="mouse-icon" width="40px" height = "60px" stroke-linecap="round" stroke-linejoin="round" stroke-width="25px" stroke="#000" fill="none"> <path fill="#fff" stroke="none" d="M827,112 h30 a140,140,0,0,1,140,140 v268 a140,140,0,0,1-140,140 h-60 a140,140,0,0,1-140-140v-268 a140,140,0,0,1,140-140h60" /> <path d="M827,112 h30 a140,140,0,0,1,140,140 v68 h-167 z" fill="#0cf" stroke="none" /> <path fill="none" d="M827,112 h30 a140,140,0,0,1,140,140 v268 a140,140,0,0,1-140,140 h-60 a140,140,0,0,1-140-140v-268 a140,140,0,0,1,140-140h60" /> <path d="M657 317 h 340 h-170 v-207" /> <ellipse fill="#fff" cx="827.57" cy="218.64" rx="29" ry="68" /> </svg>',
makeTextLog(text, time = 180) {
if (game.replaceTextLog) {

View File

@@ -2,6 +2,11 @@
/* TODO: *******************************************
*****************************************************
gun/field: portals
use the code from mines to get them to stick to walls
or lasers
alternate red and blue portals
missiles don't explode reliably enough
they can bounce, which is cool, but they should still explode right after a bounce
@@ -249,7 +254,14 @@ const build = {
},
pauseGrid() {
// let text = `<div class="pause-grid-module" style="border:0px;background:none;"></div>`
let text = `<div class="pause-grid-module"><span style="font-size:1.5em;font-weight: 600;">PAUSED</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Press P to unpause</div>`;
let text = `
<div class="pause-grid-module">
<span style="font-size:1.5em;font-weight: 600;">PAUSED</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; press P to resume
</div>`;
// <div class="pause-grid-module" style="display: flex; justify-content: space-between;padding-bottom:20px;">
// <span>${game.SVGleftMouse} fire gun</span>
// <span>${game.SVGrightMouse} use field</span>
// </div>
let countGuns = 0
let countMods = 0
for (let i = 0, len = b.guns.length; i < len; i++) {

View File

@@ -74,7 +74,7 @@ const level = {
//******************************************************************************************************************
testingMap() {
//start with all guns
level.difficultyIncrease(9) //level 7 on normal, level 4 on hard, level 1.2 on why?
// level.difficultyIncrease(9) //level 7 on normal, level 4 on hard, level 1.2 on why?
game.zoomScale = 1700 //1400 is normal
spawn.setSpawnList();
mech.setPosToSpawn(-75, -60); //normal spawn
@@ -126,8 +126,9 @@ const level = {
// powerUps.spawn(450, -400, "mod", false);
// spawn.bodyRect(-45, -100, 40, 50);
// spawn.bomber(800, -450);
spawn.hopper(400, -1050);
// spawn.starter(1200, -1050);
spawn.laserBoss(400, -750);
// spawn.laser(400, -550);
spawn.starter(1200, -1050);
// spawn.nodeBoss(-600, -550, "starter");
// spawn.starter(800, -150);
// spawn.beamer(800, -150);

View File

@@ -359,7 +359,7 @@ const mobs = {
dmg = 0.002 * game.dmgScale;
mech.damage(dmg);
//draw damage
ctx.fillStyle = color;
ctx.fillStyle = "#f00";
ctx.beginPath();
ctx.arc(best.x, best.y, dmg * 2000, 0, 2 * Math.PI);
ctx.fill();

View File

@@ -865,39 +865,27 @@ const mech = {
const dyP = mech.pos.y - powerUp[i].position.y;
const dist2 = dxP * dxP + dyP * dyP;
// float towards player if looking at and in range or if very close to player
if (dist2 < grabPowerUpRange2 && (mech.lookingAt(powerUp[i]) || dist2 < 16000)) {
// mech.fieldMeter -= mech.fieldRegen * 0.5;
if (mech.health === mech.maxHealth && powerUp[i].name === "heal" && dist2 < 16000) {
mech.fieldCDcycle = mech.cycle + 30;
//push away
Matter.Body.setVelocity(powerUp[i], {
x: powerUp[i].velocity.x * 0,
y: powerUp[i].velocity.y * 0
});
powerUp[i].force.x -= 0.0005 * dxP * powerUp[i].mass;
powerUp[i].force.y -= 0.0005 * dyP * powerUp[i].mass;
} else {
powerUp[i].force.x += 7 * (dxP / dist2) * powerUp[i].mass;
powerUp[i].force.y += 7 * (dyP / dist2) * powerUp[i].mass - powerUp[i].mass * game.g; //negate gravity
//extra friction
Matter.Body.setVelocity(powerUp[i], {
x: powerUp[i].velocity.x * 0.11,
y: powerUp[i].velocity.y * 0.11
});
if (dist2 < 5000) { //use power up if it is close enough
if (b.isModMassEnergy) {
mech.fieldMeter = mech.fieldEnergyMax;
mech.addHealth(0.05);
}
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
});
powerUp[i].effect();
Matter.World.remove(engine.world, powerUp[i]);
powerUp.splice(i, 1);
return; //because the array order is messed up after splice
if (dist2 < grabPowerUpRange2 && (mech.lookingAt(powerUp[i]) || dist2 < 16000) && !(mech.health === mech.maxHealth && powerUp[i].name === "heal")) {
powerUp[i].force.x += 7 * (dxP / dist2) * powerUp[i].mass;
powerUp[i].force.y += 7 * (dyP / dist2) * powerUp[i].mass - powerUp[i].mass * game.g; //negate gravity
//extra friction
Matter.Body.setVelocity(powerUp[i], {
x: powerUp[i].velocity.x * 0.11,
y: powerUp[i].velocity.y * 0.11
});
if (dist2 < 5000) { //use power up if it is close enough
if (b.isModMassEnergy) {
mech.fieldMeter = mech.fieldEnergyMax;
mech.addHealth(0.05);
}
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
});
powerUp[i].effect();
Matter.World.remove(engine.world, powerUp[i]);
powerUp.splice(i, 1);
return; //because the array order is messed up after splice
}
}
}

View File

@@ -4,19 +4,19 @@ const powerUps = {
choose(type, index) {
if (type === "gun") {
b.giveGuns(index)
game.replaceTextLog = true;
game.makeTextLog(`${game.SVGleftMouse} <strong style='font-size:30px;'>${b.guns[index].name}</strong><br><br>${b.guns[index].description}`, 500);
game.replaceTextLog = false;
// game.replaceTextLog = true;
// game.makeTextLog(`${game.SVGleftMouse} <strong style='font-size:30px;'>${b.guns[index].name}</strong><br><br>${b.guns[index].description}`, 500);
// game.replaceTextLog = false;
} else if (type === "field") {
mech.setField(index)
game.replaceTextLog = true;
game.makeTextLog(`${game.SVGrightMouse}<strong style='font-size:30px;'> ${mech.fieldUpgrades[mech.fieldMode].name}</strong><br><span class='faded'></span><br>${mech.fieldUpgrades[mech.fieldMode].description}`, 600);
game.replaceTextLog = false;
// game.replaceTextLog = true;
// game.makeTextLog(`${game.SVGrightMouse}<strong style='font-size:30px;'> ${mech.fieldUpgrades[mech.fieldMode].name}</strong><br><span class='faded'></span><br>${mech.fieldUpgrades[mech.fieldMode].description}`, 600);
// game.replaceTextLog = false;
} else if (type === "mod") {
b.giveMod(index)
game.replaceTextLog = true;
game.makeTextLog(`<div class="circle mod"></div> &nbsp; <strong style='font-size:30px;'>${b.mods[index].name}</strong><br><br> ${b.mods[index].description}`, 500);
game.replaceTextLog = false;
// game.replaceTextLog = true;
// game.makeTextLog(`<div class="circle mod"></div> &nbsp; <strong style='font-size:30px;'>${b.mods[index].name}</strong><br><br> ${b.mods[index].description}`, 500);
// game.replaceTextLog = false;
}
document.body.style.cursor = "none";
document.getElementById("choose-grid").style.display = "none"
@@ -139,7 +139,12 @@ const powerUps = {
function doNotHave(who, skip1 = -1, skip2 = -1, skip3 = -1) {
let options = [];
for (let i = 0; i < who.length; i++) {
if (who[i].count < who[i].maxCount && i !== skip1 && i !== skip2 && i !== skip3) options.push(i);
if (who[i].count < who[i].maxCount &&
i !== skip1 && i !== skip2 && i !== skip3 &&
(b.modCount > 4 || who[i].name !== "Born rule")
) {
options.push(i);
}
}
if (options.length > 0) return options[Math.floor(Math.random() * options.length)]
}

View File

@@ -650,7 +650,6 @@ const spawn = {
}
},
laser(x, y, radius = 30) {
//only on level 1
mobs.spawn(x, y, 3, radius, "#f00");
let me = mob[mob.length - 1];
me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front
@@ -666,6 +665,128 @@ const spawn = {
this.laser();
};
},
laserBoss(x, y, radius = 130) {
mobs.spawn(x, y, 3, radius, "#f00");
let me = mob[mob.length - 1];
me.startingPosition = {
x: x,
y: y
}
// me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front
// Matter.Body.rotate(me, Math.random() * Math.PI * 2);
Matter.Body.setDensity(me, 0.004 + 0.001 * Math.sqrt(game.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
// spawn.shield(me, x, y, 1);
me.onDeath = function () {
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
};
me.laser = function (where, angle) {
const vertexCollision = function (v1, v1End, domain) {
for (let i = 0; i < domain.length; ++i) {
let vertices = domain[i].vertices;
const len = vertices.length - 1;
for (let j = 0; j < len; j++) {
results = game.checkLineIntersection(v1, v1End, vertices[j], vertices[j + 1]);
if (results.onLine1 && results.onLine2) {
const dx = v1.x - results.x;
const dy = v1.y - results.y;
const dist2 = dx * dx + dy * dy;
if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) best = {
x: results.x,
y: results.y,
dist2: dist2,
who: domain[i],
v1: vertices[j],
v2: vertices[j + 1]
};
}
}
results = game.checkLineIntersection(v1, v1End, vertices[0], vertices[len]);
if (results.onLine1 && results.onLine2) {
const dx = v1.x - results.x;
const dy = v1.y - results.y;
const dist2 = dx * dx + dy * dy;
if (dist2 < best.dist2) best = {
x: results.x,
y: results.y,
dist2: dist2,
who: domain[i],
v1: vertices[0],
v2: vertices[len]
};
}
}
};
const seeRange = 4000;
best = {
x: null,
y: null,
dist2: Infinity,
who: null,
v1: null,
v2: null
};
const look = {
x: where.x + seeRange * Math.cos(angle),
y: where.y + seeRange * Math.sin(angle)
};
vertexCollision(where, look, mob);
vertexCollision(where, look, map);
vertexCollision(where, look, body);
if (!mech.isStealth) vertexCollision(where, look, [player]);
//hitting mob
if (best.who) {
if (best.who.mob) {
// dmg = 0.03 * game.dmgScale;
best.who.damage(0.1);
//draw damage
game.drawList.push({ //add dmg to draw queue
x: best.x,
y: best.y,
radius: Math.sqrt(dmg) * 50,
color: game.playerDmgColor,
time: game.drawTime
});
}
// hitting player
if (best.who === player) {
dmg = 0.03 * game.dmgScale;
mech.damage(dmg);
//draw damage
game.drawList.push({ //add dmg to draw queue
x: best.x,
y: best.y,
radius: dmg * 2000,
color: game.mobDmgColor,
time: game.drawTime
});
}
}
//draw beam
if (best.dist2 === Infinity) best = look;
ctx.moveTo(where.x, where.y);
ctx.lineTo(best.x, best.y);
}
me.do = function () {
this.torque = this.lookTorque * this.inertia * 0.2;
Matter.Body.setVelocity(this, {
x: 0,
y: 0
});
Matter.Body.setPosition(this, this.startingPosition);
ctx.beginPath();
this.laser(this.vertices[0], this.angle + Math.PI / 3);
this.laser(this.vertices[1], this.angle + Math.PI);
this.laser(this.vertices[2], this.angle - Math.PI / 3);
ctx.strokeStyle = "#f00"; // Purple path
ctx.lineWidth = 3;
ctx.setLineDash([50 + 120 * Math.random(), 55 * Math.random()]);
ctx.stroke(); // Draw it
ctx.setLineDash([0, 0]);
// this.laser(this.vertices[2], this.angle + Math.PI / 3);
};
},
striker(x, y, radius = 14 + Math.ceil(Math.random() * 25)) {
mobs.spawn(x, y, 5, radius, "rgb(221,102,119)");
let me = mob[mob.length - 1];