mod - impact shear

mod - negative mass field: 80%->90% harm reduction while active, but 2x energy drain
mod - mobs fire nails when they die  (by Francois 👑 from discord)
This commit is contained in:
landgreen
2020-04-30 12:17:17 -07:00
parent a7faffa8a7
commit 9a719d3f2d
7 changed files with 172 additions and 188 deletions

View File

@@ -83,6 +83,8 @@ const b = {
isModRPG: null,
isMod3Missiles: null,
isModDeterminism: null,
isModHarmReduce: null,
modNailsDeathMob: null,
modOnHealthChange() { //used with acid mod
if (b.isModAcidDmg && mech.health > 0.8) {
b.modAcidDmg = 0.5
@@ -407,6 +409,22 @@ const b = {
b.isModExplodeMob = false;
}
},
{
name: "impact shear",
description: "mobs release <strong>+2</strong> <strong>nails</strong> when they <strong>die</strong><br>nails target nearby mobs",
maxCount: 9,
count: 0,
allowed() {
return true
},
requires: "",
effect: () => {
b.modNailsDeathMob += 2
},
remove() {
b.modNailsDeathMob = 0;
}
},
{
name: "reaction inhibitor",
description: "mobs <strong>die</strong> if their life goes below <strong>12%</strong>",
@@ -1405,6 +1423,22 @@ const b = {
b.isModPlasmaRange = 1;
}
},
{
name: "degenerate matter",
description: "<strong>2x</strong> <strong class='color-f'>energy</strong> drain for <strong>negative mass field</strong><br>increase <strong>harm</strong> reduction to <strong>90%</strong>",
maxCount: 1,
count: 0,
allowed() {
return mech.fieldUpgrades[mech.fieldMode].name === "negative mass field"
},
requires: "negative mass field",
effect() {
b.isModHarmReduce = true
},
remove() {
b.isModHarmReduce = false;
}
},
{
name: "annihilation",
description: "after <strong>touching</strong> mobs, they are <strong>annihilated</strong>",
@@ -2081,35 +2115,7 @@ const b = {
},
onEnd() {
if (this.isArmed) {
const targets = [] //target nearby mobs
for (let i = 0, len = mob.length; i < len; i++) {
if (mob[i].dropPowerUp) {
const dist = Vector.magnitudeSquared(Vector.sub(this.position, mob[i].position));
if (dist < 1440000 && //1200*1200
Matter.Query.ray(map, this.position, mob[i].position).length === 0 &&
Matter.Query.ray(body, this.position, mob[i].position).length === 0) {
targets.push(Vector.add(mob[i].position, Vector.mult(mob[i].velocity, Math.sqrt(dist) / 60))) //predict where the mob will be in a few cycles
}
}
}
for (let i = 0; i < 14; i++) {
const speed = 53 + 10 * Math.random()
if (targets.length > 0) { // aim near a random target in array
const index = Math.floor(Math.random() * targets.length)
const SPREAD = 150 / targets.length
const WHERE = {
x: targets[index].x + SPREAD * (Math.random() - 0.5),
y: targets[index].y + SPREAD * (Math.random() - 0.5)
}
b.nail(this.position, Vector.mult(Vector.normalise(Vector.sub(WHERE, this.position)), speed), 1.1)
} else { // aim in random direction
const ANGLE = 2 * Math.PI * Math.random()
b.nail(this.position, {
x: speed * Math.cos(ANGLE),
y: speed * Math.sin(ANGLE)
})
}
}
b.targetedNail(this.position, 14)
}
if (isAmmoBack) { //get ammo back from b.isModMineAmmoBack
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
@@ -2371,6 +2377,36 @@ const b = {
y: speed * Math.sin(dir)
});
},
targetedNail(position, num = 1, speed = 50 + 10 * Math.random(), range = 1200) {
const targets = [] //target nearby mobs
for (let i = 0, len = mob.length; i < len; i++) {
if (mob[i].dropPowerUp) {
const dist = Vector.magnitude(Vector.sub(position, mob[i].position));
if (dist < range &&
Matter.Query.ray(map, position, mob[i].position).length === 0 &&
Matter.Query.ray(body, position, mob[i].position).length === 0) {
targets.push(Vector.add(mob[i].position, Vector.mult(mob[i].velocity, dist / 60))) //predict where the mob will be in a few cycles
}
}
}
for (let i = 0; i < num; i++) {
if (targets.length > 0) { // aim near a random target in array
const index = Math.floor(Math.random() * targets.length)
const SPREAD = 150 / targets.length
const WHERE = {
x: targets[index].x + SPREAD * (Math.random() - 0.5),
y: targets[index].y + SPREAD * (Math.random() - 0.5)
}
b.nail(position, Vector.mult(Vector.normalise(Vector.sub(WHERE, position)), speed), 1.1)
} else { // aim in random direction
const ANGLE = 2 * Math.PI * Math.random()
b.nail(position, {
x: speed * Math.cos(ANGLE),
y: speed * Math.sin(ANGLE)
})
}
}
},
nail(pos, velocity, dmg = 0) {
const me = bullet.length;
bullet[me] = Bodies.rectangle(pos.x, pos.y, 25, 2, b.fireAttributes(Math.atan2(velocity.y, velocity.x)));
@@ -2939,7 +2975,7 @@ const b = {
fire() {
if (b.isMod3Missiles) {
if (mech.crouch) {
mech.fireCDcycle = mech.cycle + 80; // cool down
mech.fireCDcycle = mech.cycle + 80 * b.modFireRate; // cool down
const direction = {
x: Math.cos(mech.angle),
y: Math.sin(mech.angle)
@@ -2955,7 +2991,7 @@ const b = {
bullet[bullet.length - 1].force.y += push.y * (i - 1);
}
} else {
mech.fireCDcycle = mech.cycle + 60; // cool down
mech.fireCDcycle = mech.cycle + 60 * b.modFireRate; // cool down
const direction = {
x: Math.cos(mech.angle),
y: Math.sin(mech.angle)
@@ -2972,7 +3008,7 @@ const b = {
}
}
} else {
mech.fireCDcycle = mech.cycle + Math.floor(mech.crouch ? 50 : 30); // cool down
mech.fireCDcycle = mech.cycle + Math.floor(mech.crouch ? 50 : 30) * b.modFireRate; // cool down
b.missile({
x: mech.pos.x + 40 * Math.cos(mech.angle),
y: mech.pos.y + 40 * Math.sin(mech.angle) - 3
@@ -3046,37 +3082,7 @@ const b = {
bullet[me].explodeRad = 275;
bullet[me].onEnd = function () {
b.explosion(this.position, this.explodeRad); //makes bullet do explosive damage at end
if (b.modGrenadeFragments) {
const targets = [] //target nearby mobs
for (let i = 0, len = mob.length; i < len; i++) {
if (mob[i].dropPowerUp) {
const dist = Vector.magnitudeSquared(Vector.sub(this.position, mob[i].position));
if (dist < 1440000 && //1200*1200
Matter.Query.ray(map, this.position, mob[i].position).length === 0 &&
Matter.Query.ray(body, this.position, mob[i].position).length === 0) {
targets.push(Vector.add(mob[i].position, Vector.mult(mob[i].velocity, Math.sqrt(dist) / 60))) //predict where the mob will be in a few cycles
}
}
}
for (let i = 0; i < b.modGrenadeFragments; i++) {
const speed = 53 + 10 * Math.random()
if (targets.length > 0) { // aim near a random target in array
const index = Math.floor(Math.random() * targets.length)
const SPREAD = 150 / targets.length
const WHERE = {
x: targets[index].x + SPREAD * (Math.random() - 0.5),
y: targets[index].y + SPREAD * (Math.random() - 0.5)
}
b.nail(this.position, Vector.mult(Vector.normalise(Vector.sub(WHERE, this.position)), speed), 1.1)
} else { // aim in random direction
const ANGLE = 2 * Math.PI * Math.random()
b.nail(this.position, {
x: speed * Math.cos(ANGLE),
y: speed * Math.sin(ANGLE)
})
}
}
}
if (b.modGrenadeFragments) b.targetedNail(this.position, b.modGrenadeFragments)
}
bullet[me].minDmgSpeed = 1;
bullet[me].onDmg = function () {
@@ -3305,7 +3311,7 @@ const b = {
name: "drones",
description: "deploy drones that <strong>crash</strong> into mobs<br>collisions reduce their <strong>lifespan</strong> by 1 second",
ammo: 0,
ammoPack: 13,
ammoPack: 14,
have: false,
isStarterGun: true,
isEasyToAim: true,
@@ -3476,13 +3482,7 @@ const b = {
if (who.shield) {
for (let i = 0, len = mob.length; i < len; i++) {
if (mob[i].id === who.shieldTargetID) { //apply some knock back to shield mob before shield breaks
Matter.Body.setVelocity(mob[i], Matter.Vector.mult(Matter.Vector.normalise(this.velocity), 10));
// const force = Matter.Vector.mult(this.velocity, 4 / mob[i].mass)
// const velocity = Matter.Vector.add(force, mob[i].velocity)
// Matter.Body.setVelocity(mob[i], velocity);
break
}
}
@@ -3493,35 +3493,7 @@ const b = {
Matter.Body.setDensity(this, 0.001);
}
if (b.isModRailNails && this.speed > 10) {
const targets = [] //target nearby mobs
for (let i = 0, len = mob.length; i < len; i++) {
if (mob[i].dropPowerUp) {
const dist = Vector.magnitudeSquared(Vector.sub(this.position, mob[i].position));
if (dist < 1000000 && //1000*1000
Matter.Query.ray(map, this.position, mob[i].position).length === 0 &&
Matter.Query.ray(body, this.position, mob[i].position).length === 0) {
targets.push(Vector.add(mob[i].position, Vector.mult(mob[i].velocity, Math.sqrt(dist) / 60))) //predict where the mob will be in a few cycles
}
}
}
for (let i = 0; i < this.speed - 10; i++) {
const speed = 50 + 10 * Math.random()
if (targets.length > 0) { // aim near a random target in array
const index = Math.floor(Math.random() * targets.length)
const SPREAD = 150 / targets.length
const WHERE = {
x: targets[index].x + SPREAD * (Math.random() - 0.5),
y: targets[index].y + SPREAD * (Math.random() - 0.5)
}
b.nail(this.position, Vector.mult(Vector.normalise(Vector.sub(WHERE, this.position)), speed), 1.1)
} else { // aim in random direction
const ANGLE = 2 * Math.PI * Math.random()
b.nail(this.position, {
x: speed * Math.cos(ANGLE),
y: speed * Math.sin(ANGLE)
})
}
}
b.targetedNail(this.position, Math.min(40, this.speed) - 10)
this.endCycle = 0 //triggers despawn
}
},

View File

@@ -67,6 +67,8 @@ const game = {
mech.cycle++;
game.gravity();
Engine.update(engine, game.delta);
mech.keyMove();
level.checkZones();
level.checkQuery();
mech.move();

View File

@@ -19,13 +19,14 @@ const level = {
// b.giveGuns("foam")
// mech.setField("time dilation field")
// b.giveMod("renormalization");
// b.giveMod("quantum tunneling");
// b.giveGuns("rail gun")
// b.giveMod("impact shear");
// b.giveMod("nail bot");
// b.giveGuns("mine")
// mech.setField("pilot wave")
// mech.setField("perfect diamagnetism")
// level.intro(); //starting level
level.testing();
level.intro(); //starting level
// level.testing();
// level.stronghold()
// level.bosses();
// level.satellite();
@@ -157,11 +158,11 @@ const level = {
// spawn.bomberBoss(2900, -500)
// spawn.suckerBoss(1200, -500)
// spawn.hopper(1200, -500, 70)
// spawn.hopper(1200, -500, 100)
spawn.spinner(1200, -500)
// spawn.shield(mob[mob.length - 1], 1200, -500, 1);
// spawn.nodeBoss(1200, -500, "spiker")
spawn.spiderBoss(1200, -500)
// spawn.spiderBoss(1200, -500)
// spawn.timeSkipBoss(2900, -500)
// spawn.randomMob(1600, -500)
},
@@ -987,8 +988,7 @@ const level = {
stiffness: 0.00007
});
if (game.difficulty > 4) spawn.nodeBoss(4250, 0, "spawns", 8, 20, 105); //chance to spawn a ring of exploding mobs around this boss
}
if (Math.random() < 0.08) {
} else if (Math.random() < 0.08) {
spawn.randomLevelBoss(4250, -250);
} else {
//floor below right tall tower
@@ -1721,7 +1721,7 @@ const level = {
}
}
},
stronghold() { // player made level by Francois 👑 from discord
stronghold() { // player made level by Francois 👑 from discord
level.defaultZoom = 1400
game.zoomTransition(level.defaultZoom)
@@ -1768,6 +1768,13 @@ const level = {
height: 1700,
color: "rgba(0,0,0,0.1)"
});
level.fillBG.push({
x: 1100,
y: -1700,
width: 50,
height: 450,
color: "rgba(0,0,0,0.1)"
});
level.fillBG.push({
x: 1050,
y: -1200,
@@ -1792,7 +1799,7 @@ const level = {
level.fillBG.push({
x: 2530,
y: -550,
width: 400,
width: 430,
height: -1450,
color: "rgba(0,0,0,0.1)"
});
@@ -1873,15 +1880,15 @@ const level = {
spawn.bodyRect(3400, -1470, 110, 70); //Moyen bloc dans la cuve
spawn.mapRect(3270, -1750, 80, 50); // Rebord gauche cuve
spawn.mapRect(2530, -2000, 400, 50); //First Plateforme
spawn.mapRect(2530, -2000, 430, 50); //First Plateforme
spawn.mapRect(1600, -1750, 600, 50); // Middle plateforme
spawn.mapRect(1150, -1750, 250, 50); //Derniere plateforme // Toit petite boite en [
spawn.mapRect(1100, -1750, 300, 50); //Derniere plateforme // Toit petite boite en [
spawn.bodyRect(1830, -1980, 190, 230); // Fat bloc plateforme middle
spawn.bodyRect(1380, -1770, 250, 20) // Pont last plateforme
spawn.mapRect(1000, -1250, 400, 50); //Sol de la petite boite en [
spawn.mapRect(1100, -1750, 50, 380); //Mur gauche petite boite en [
spawn.bodyRect(1100, -1380, 48, 119); //Bloc-porte petite boite en [
spawn.mapRect(1100, -1550, 50, 190); //Mur gauche petite boite en [
spawn.bodyRect(1100, -1380, 48, 109); //Bloc-porte petite boite en [
spawn.mapRect(-100, -750, 1100, 50); //Sol last salle
spawn.mapRect(1000, -1200, 50, 500) // Mur droit last salle
@@ -1897,7 +1904,9 @@ const level = {
spawn.bodyRect(-503, -1250, 30, 30); // Petit bloc exit room
spawn.mapRect(500, -700, 100, 590); //Bloc noir un dessous last salle
spawn.mapRect(1400, -250, 200, 250); //Black Block left from the spawn
spawn.mapRect(1350, -250, 250, 250); //Black Block left from the spawn
spawn.boost(1470, -250, 1080);
spawn.boost(-370, 0, 800);
map[map.length] = Bodies.polygon(2325, -205, 0, 15); //circle above door
@@ -1920,12 +1929,19 @@ const level = {
spawn.bodyRect(2545, -50, 70, 50);
spawn.bodyRect(2550, 0, 100, 30);
spawn.randomSmallMob(200, -1300, 0.5);
spawn.randomSmallMob(300, -1300, 0.9);
spawn.randomSmallMob(470, -650, 1);
spawn.randomSmallMob(1000, -400, 1);
spawn.randomSmallMob(2550, -560, 1);
spawn.randomSmallMob(3350, -900, 1);
spawn.randomSmallMob(3600, -1210, 1);
spawn.randomSmallMob(700, -1950, 0.2);
spawn.randomSmallMob(5050, -550);
spawn.randomMob(-250, -250, 0.8);
spawn.randomMob(-300, -600, 0.6);
spawn.randomMob(350, -900, 0.5);
spawn.randomMob(770, -950, 0.8)
spawn.randomMob(900, -160, 1);
spawn.randomMob(2360, -820, 0.8);
spawn.randomMob(2700, -2020, 0.8);
@@ -1935,6 +1951,7 @@ const level = {
spawn.randomBoss(1500, -1900, 0.5);
spawn.randomBoss(2350, -850, 1);
spawn.randomBoss(100, -450, 0.9);
if (game.difficulty > 3) spawn.randomLevelBoss(1850, -1400, 1);
},
//*****************************************************************************************************************

View File

@@ -996,6 +996,7 @@ const mobs = {
if (mech.energy > 0.33) mech.energy -= 0.33
}
if (b.isModExplodeMob) b.explosion(this.position, Math.min(450, Math.sqrt(this.mass + 3) * 80))
if (b.modNailsDeathMob) b.targetedNail(this.position, b.modNailsDeathMob)
}
},
removeConsBB() {

View File

@@ -1461,9 +1461,16 @@ const mech = {
} else if ((keys[32] || game.mouseDownRight) && mech.fieldCDcycle < mech.cycle) { //push away
mech.grabPowerUp();
mech.lookForPickUp();
const DRAIN = 0.00035
let DRAIN = 0.00105;
if (mech.energy > DRAIN) {
mech.fieldDamageResistance = 0.2; // 1 - 0.8
if (b.isModHarmReduce) {
mech.fieldDamageResistance = 0.1; // 1 - 0.9
DRAIN = 0.0007 //2x energy drain
} else {
mech.fieldDamageResistance = 0.2; // 1 - 0.8
DRAIN = 0.00035
}
// mech.pushMobs360();
//repulse mobs

View File

@@ -81,8 +81,7 @@ const spawn = {
},
randomLevelBoss(x, y) {
// suckerBoss, laserBoss, tetherBoss, snakeBoss all need a particular level to work so they are not included
const options = ["spiderBoss"] //, "timeSkipBoss" //"shooterBoss", "cellBossCulture", "bomberBoss",
// const options = ["timeSkipBoss"]
const options = ["shooterBoss", "cellBossCulture", "bomberBoss", "spiderBoss"] // , "timeSkipBoss"
spawn[options[Math.floor(Math.random() * options.length)]](x, y)
},
//mob templates *********************************************************************************************
@@ -420,55 +419,49 @@ const spawn = {
let me = mob[mob.length - 1];
me.fill = "#28b";
me.rememberFill = me.fill;
me.cdBurst1 = 0; //must add for burstAttraction
me.cdBurst2 = 0; //must add for burstAttraction
me.delay = 0;
me.cd = 0;
me.burstDir = {
x: 0,
y: 0
};
me.accelMag = 0.16 * game.accelScale;
me.frictionAir = 0.022;
me.lookTorque = 0.0000014;
me.restitution = 0;
spawn.shield(me, x, y);
me.do = function () {
me.look = function () {
this.seePlayerByLookingAt();
this.checkStatus();
//accelerate towards the player after a delay
if (this.seePlayer.recall) {
if (this.cdBurst2 < game.cycle && this.angularSpeed < 0.01) {
this.cdBurst2 = Infinity;
this.cdBurst1 = game.cycle + 40;
this.burstDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position));
} else if (this.cdBurst1 < game.cycle) {
this.cdBurst2 = game.cycle + this.delay;
this.cdBurst1 = Infinity;
this.force = Vector.mult(this.burstDir, this.mass * 0.25);
this.fill = this.rememberFill;
} else if (this.cdBurst1 != Infinity) {
this.torque += 0.000035 * this.inertia;
this.fill = randomColor({
hue: "blue"
});
//draw attack vector
const mag = this.radius * 2.5 + 50;
ctx.strokeStyle = "rgba(0,0,0,0.2)";
ctx.lineWidth = 3;
ctx.setLineDash([10, 20]); //30
const dir = Vector.add(this.position, Vector.mult(this.burstDir, mag));
ctx.beginPath();
ctx.moveTo(this.position.x, this.position.y);
ctx.lineTo(dir.x, dir.y);
ctx.stroke();
ctx.setLineDash([]);
} else {
this.fill = this.rememberFill;
}
} else {
this.cdBurst2 = 0;
if (this.seePlayer.recall && this.cd < game.cycle) {
this.burstDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position));
this.cd = game.cycle + 40;
this.do = this.spin
}
};
}
me.do = me.look
me.spin = function () {
this.checkStatus();
this.torque += 0.000035 * this.inertia;
this.fill = randomColor({
hue: "blue"
});
//draw attack vector
const mag = this.radius * 2.5 + 50;
ctx.strokeStyle = "rgba(0,0,0,0.2)";
ctx.lineWidth = 3;
ctx.setLineDash([10, 20]); //30
const dir = Vector.add(this.position, Vector.mult(this.burstDir, mag));
ctx.beginPath();
ctx.moveTo(this.position.x, this.position.y);
ctx.lineTo(dir.x, dir.y);
ctx.stroke();
ctx.setLineDash([]);
if (this.cd < game.cycle) {
this.fill = this.rememberFill;
this.cd = game.cycle + 180 * game.CDScale
this.do = this.look
this.force = Vector.mult(this.burstDir, this.mass * 0.25);
}
}
},
sucker(x, y, radius = 30 + Math.ceil(Math.random() * 70)) {
radius = 9 + radius / 8; //extra small
@@ -714,18 +707,18 @@ const spawn = {
});
}
},
timeSkipBoss(x, y, radius = 70) {
timeSkipBoss(x, y, radius = 55) {
mobs.spawn(x, y, 6, radius, '#000');
let me = mob[mob.length - 1];
// me.stroke = "transparent"; //used for drawSneaker
me.timeSkipLastCycle = 0
me.eventHorizon = 1600; //required for black hole
me.eventHorizon = 1800; //required for black hole
me.seeAtDistance2 = (me.eventHorizon + 2000) * (me.eventHorizon + 2000); //vision limit is event horizon + 2000
me.accelMag = 0.0004 * game.accelScale;
// me.frictionAir = 0.005;
// me.memory = 1600;
// Matter.Body.setDensity(me, 0.02); //extra dense //normal is 0.001 //makes effective life much larger
Matter.Body.setDensity(me, 0.0025 + 0.0007 * Math.sqrt(game.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
Matter.Body.setDensity(me, 0.0015 + 0.0005 * Math.sqrt(game.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
spawn.shield(me, x, y, 1);

View File

@@ -1,16 +1,24 @@
large mods shrink on death instead of disappearing
new boss mob: spiderBoss
mod - Bayesian interference -> determinism
spawn 4 mods and 2 heals, future power ups are limited to one choice
mod - Leveraged investments -> Bayesian interference
33% chance for double power ups to drop, remove all future ammo power ups
(serious progress on my level construction tools, but it's not ready yet)
mod - negative mass field: 80%->90% harm reduction while active, but 2x energy drain
mod - mobs fire nails when they die (by Francois 👑 from discord)
************** TODO - n-gon **************
possible names for mods
Hypergolic - A hypergolic propellant combination used in a rocket engine is one whose components spontaneously ignite when they come into contact with each other.
have a mob apply a positive status effect on other mobs,
heal?
make it yellow
damage bonus, but how?
possible balance issues
mobs that fire grenades
mobs that fire bullets
bullets that chase the player a bit (blue color)
short lived bullets that fire in every direction
or fire in a spiral over time
construct
display outline of map to be draw while mouse is down
toggle between maps and bodies
@@ -18,25 +26,6 @@ construct
display current output text in a box
live update it
mod - blocking with perfect diamagnetism fires your gun
maybe doesn't trigger cooldown?
does use ammo
mod - annihilation might be unbalanced?
boss mob - let it die multiple times and come back to life
on death event spawns a new version of self, but with a decrementing counter
foam - check for touching map / blocks and slow foam down rather then bounce off walls
quantum foam should just skip the shield
red flashes when you take damage were replaced with the color of your energy bar
When you have mass energy equivalence
mod - missiles: fire 3 small missiles
disables missile replication mod
lore - a robot (the player) gains self awareness
each mod/gun/field is a new tech
all the technology leads to the singularity
@@ -57,9 +46,12 @@ atmosphere levels: change the pace, give the user a rest between combat
simple puzzles
cool looking stuff
large rotating fan that the player has to move through
nonaggressive mobs
in the final level you see your self at the starting level, with the wires
you shoot your self to wake up?
nonaggressive mobs
boss mob - let it die multiple times and come back to life
on death event spawns a new version of self, but with a decrementing counter
bullets cost 5 life instead of ammo, but return 5 life when they hit a mob
replace life with energy or ammo?