many worlds mod

This commit is contained in:
landgreen
2020-05-14 09:01:24 -07:00
parent f89bb09b37
commit 30518de6cb
10 changed files with 216 additions and 97 deletions

View File

@@ -87,6 +87,7 @@ const b = {
modNailsDeathMob: null, modNailsDeathMob: null,
isModSlowFPS: null, isModSlowFPS: null,
isModNeutronStun: null, isModNeutronStun: null,
manyWorlds: null,
modOnHealthChange() { //used with acid mod modOnHealthChange() { //used with acid mod
if (b.isModAcidDmg && mech.health > 0.8) { if (b.isModAcidDmg && mech.health > 0.8) {
b.modAcidDmg = 0.5 b.modAcidDmg = 0.5
@@ -762,7 +763,7 @@ const b = {
}, },
{ {
name: "pair production", name: "pair production",
description: "<strong>power ups</strong> overfill your <strong class='color-f'>energy</strong><br>temporarily gain <strong>twice</strong> your maximum", description: "<strong>power ups</strong> overfill your <strong class='color-f'>energy</strong><br>temporarily gain <strong>twice</strong> your max <strong class='color-f'>energy</strong>",
maxCount: 1, maxCount: 1,
count: 0, count: 0,
allowed() { allowed() {
@@ -850,31 +851,23 @@ const b = {
} }
}, },
{ {
name: "reallocation", name: "many worlds",
description: "convert <strong>1</strong> random <strong class='color-m'>mod</strong> into <strong>2</strong> new <strong>guns</strong><br><em>recursive mods lose all stacks</em>", description: "spawn a <strong class='color-r'>reroll</strong> after choosing a power up",
maxCount: 1, maxCount: 1,
count: 0, count: 0,
allowed() { allowed() {
return (b.modCount > 0) && !build.isCustomSelection return true
}, },
requires: "at least 1 mod", requires: "",
effect: () => { effect: () => {
const have = [] //find which mods you have b.manyWorlds = true;
for (let i = 0; i < b.mods.length; i++) { // for (let i = 0; i < 9; i++) {
if (b.mods[i].count > 0) have.push(i) // powerUps.spawn(mech.pos.x, mech.pos.y, "reroll");
} // if (Math.random() < b.modBayesian) powerUps.spawn(mech.pos.x, mech.pos.y, "reroll");
const choose = have[Math.floor(Math.random() * have.length)] // }
b.mods[choose].remove(); // remove a random mod form the list of mods you have
b.mods[choose].count = 0;
game.updateModHUD();
for (let i = 0; i < 2; i++) {
powerUps.spawn(mech.pos.x, mech.pos.y, "gun");
if (Math.random() < b.modBayesian) powerUps.spawn(mech.pos.x, mech.pos.y, "gun");
}
}, },
remove() { remove() {
//nothing to remove b.manyWorlds = false;
} }
}, },
{ {
@@ -903,6 +896,34 @@ const b = {
//nothing to undo //nothing to undo
} }
}, },
{
name: "reallocation",
description: "convert <strong>1</strong> random <strong class='color-m'>mod</strong> into <strong>2</strong> new <strong>guns</strong><br><em>recursive mods lose all stacks</em>",
maxCount: 1,
count: 0,
allowed() {
return (b.modCount > 0) && !build.isCustomSelection
},
requires: "at least 1 mod",
effect: () => {
const have = [] //find which mods you have
for (let i = 0; i < b.mods.length; i++) {
if (b.mods[i].count > 0) have.push(i)
}
const choose = have[Math.floor(Math.random() * have.length)]
b.mods[choose].remove(); // remove a random mod form the list of mods you have
b.mods[choose].count = 0;
game.updateModHUD();
for (let i = 0; i < 2; i++) {
powerUps.spawn(mech.pos.x, mech.pos.y, "gun");
if (Math.random() < b.modBayesian) powerUps.spawn(mech.pos.x, mech.pos.y, "gun");
}
},
remove() {
//nothing to remove
}
},
{ {
name: "Lorentzian topology", name: "Lorentzian topology",
description: "your <strong>bullets</strong> last <strong>+33% longer</strong>", description: "your <strong>bullets</strong> last <strong>+33% longer</strong>",
@@ -1973,6 +1994,7 @@ const b = {
dist = Vector.magnitude(sub) - mob[i].radius; dist = Vector.magnitude(sub) - mob[i].radius;
if (dist < radius) { if (dist < radius) {
if (mob[i].shield) dmg *= 3 //balancing explosion dmg to shields if (mob[i].shield) dmg *= 3 //balancing explosion dmg to shields
if (Matter.Query.ray(map, mob[i].position, where).length > 0) dmg *= 0.5 //reduce damage if a wall is in the way
mob[i].damage(dmg * damageScale); mob[i].damage(dmg * damageScale);
mob[i].locatePlayer(); mob[i].locatePlayer();
knock = Vector.mult(Vector.normalise(sub), (-Math.sqrt(dmg * damageScale) * mob[i].mass) / 50); knock = Vector.mult(Vector.normalise(sub), (-Math.sqrt(dmg * damageScale) * mob[i].mass) / 50);
@@ -2353,7 +2375,7 @@ const b = {
friction: 0.05, friction: 0.05,
frictionAir: 0.0005, frictionAir: 0.0005,
restitution: 1, restitution: 1,
dmg: 0.17, //damage done in addition to the damage from momentum dmg: 0.23, //damage done in addition to the damage from momentum
lookFrequency: 107 + Math.floor(47 * Math.random()), lookFrequency: 107 + Math.floor(47 * Math.random()),
endCycle: game.cycle + Math.floor((1200 + 420 * Math.random()) * b.isModBulletsLastLonger), endCycle: game.cycle + Math.floor((1200 + 420 * Math.random()) * b.isModBulletsLastLonger),
classType: "bullet", classType: "bullet",
@@ -2365,7 +2387,14 @@ const b = {
lockedOn: null, lockedOn: null,
isFollowMouse: true, isFollowMouse: true,
deathCycles: 110 + RADIUS * 5, deathCycles: 110 + RADIUS * 5,
onDmg() { onDmg(who) {
//move away from target after hitting
const unit = Vector.mult(Vector.normalise(Vector.sub(this.position, who.position)), -20)
Matter.Body.setVelocity(this, {
x: unit.x,
y: unit.y
});
this.lockedOn = null this.lockedOn = null
if (this.endCycle > game.cycle + this.deathCycles && b.isModDroneCollide) { if (this.endCycle > game.cycle + this.deathCycles && b.isModDroneCollide) {
this.endCycle -= 60 this.endCycle -= 60
@@ -3119,7 +3148,7 @@ const b = {
// check if inside a mob // check if inside a mob
q = Matter.Query.point(mob, this.position) q = Matter.Query.point(mob, this.position)
for (let i = 0; i < q.length; i++) { for (let i = 0; i < q.length; i++) {
let dmg = b.dmgScale * 0.43 / Math.sqrt(q[i].mass) * (b.modWaveHelix === 1 ? 1 : 0.6) //1 - 0.4 = 0.6 for helix mod 40% damage reduction let dmg = b.dmgScale * 0.40 / Math.sqrt(q[i].mass) * (b.modWaveHelix === 1 ? 1 : 0.6) //1 - 0.4 = 0.6 for helix mod 40% damage reduction
q[i].damage(dmg); q[i].damage(dmg);
q[i].foundPlayer(); q[i].foundPlayer();
game.drawList.push({ //add dmg to draw queue game.drawList.push({ //add dmg to draw queue
@@ -3631,11 +3660,10 @@ const b = {
//aoe damage to mobs //aoe damage to mobs
for (let i = 0, len = mob.length; i < len; i++) { for (let i = 0, len = mob.length; i < len; i++) {
if (Vector.magnitude(Vector.sub(mob[i].position, this.position)) < this.damageRadius) { if (Vector.magnitude(Vector.sub(mob[i].position, this.position)) < this.damageRadius) {
if (mob[i].shield) { let dmg = b.dmgScale * 0.023
mob[i].damage(5 * b.dmgScale * 0.023); if (Matter.Query.ray(map, mob[i].position, this.position).length > 0) dmg *= 0.5 //reduce damage if a wall is in the way
} else { if (mob[i].shield) dmg *= 5 //x5 to make up for the /5 that shields normally take
mob[i].damage(b.dmgScale * 0.023); mob[i].damage(dmg);
}
mob[i].locatePlayer(); mob[i].locatePlayer();
} }
} }
@@ -3859,6 +3887,7 @@ const b = {
//frictionAir: 0.01, //restitution: 0, //frictionAir: 0.01, //restitution: 0,
// angle: 0, // angle: 0,
// friction: 0.5, // friction: 0.5,
restitution: 0,
frictionAir: 0, frictionAir: 0,
dmg: 0, //damage done in addition to the damage from momentum dmg: 0, //damage done in addition to the damage from momentum
classType: "bullet", classType: "bullet",

View File

@@ -56,6 +56,7 @@ const game = {
b.bulletDraw(); b.bulletDraw();
b.bulletDo(); b.bulletDo();
game.drawCircle(); game.drawCircle();
game.clip();
ctx.restore(); ctx.restore();
game.drawCursor(); game.drawCursor();
}, },
@@ -132,6 +133,9 @@ const game = {
// }; // };
// requestAnimationFrame(normalFPS); // requestAnimationFrame(normalFPS);
// }, // },
clip() {
},
drawCursor() { drawCursor() {
const size = 10; const size = 10;
ctx.beginPath(); ctx.beginPath();
@@ -481,6 +485,7 @@ const game = {
b.setupAllMods(); //sets mods to default values b.setupAllMods(); //sets mods to default values
game.updateModHUD(); game.updateModHUD();
powerUps.reroll.rerolls = 0;
mech.maxHealth = 1 mech.maxHealth = 1
mech.maxEnergy = 1 mech.maxEnergy = 1
game.paused = false; game.paused = false;

View File

@@ -87,8 +87,6 @@ const build = {
<br>global damage increase: ${((b.damageFromMods()-1)*100).toFixed(0)}% <br>global damage increase: ${((b.damageFromMods()-1)*100).toFixed(0)}%
<br>global harm reduction: ${((1-mech.harmReduction())*100).toFixed(0)}% <br>global harm reduction: ${((1-mech.harmReduction())*100).toFixed(0)}%
</div>`; </div>`;
let countGuns = 0 let countGuns = 0
let countMods = 0 let countMods = 0
for (let i = 0, len = b.guns.length; i < len; i++) { for (let i = 0, len = b.guns.length; i < len; i++) {
@@ -269,10 +267,6 @@ const build = {
document.getElementById("build-grid").style.display = "grid" document.getElementById("build-grid").style.display = "grid"
}, },
shareURL() { shareURL() {
game.copyToClipBoard(build.generateURL())
alert('n-gon build URL copied to clipboard.\nPaste into browser address bar.')
},
generateURL() {
let url = "https://landgreen.github.io/sidescroller/index.html?" let url = "https://landgreen.github.io/sidescroller/index.html?"
let count = 0; let count = 0;
for (let i = 0; i < b.guns.length; i++) { for (let i = 0; i < b.guns.length; i++) {
@@ -292,7 +286,8 @@ const build = {
url += `&difficulty=${game.difficultyMode}` url += `&difficulty=${game.difficultyMode}`
url += `&level=${Number(document.getElementById("starting-level").value)}` url += `&level=${Number(document.getElementById("starting-level").value)}`
console.log(url) console.log(url)
return url game.copyToClipBoard(url)
alert('n-gon build URL copied to clipboard.\nPaste into browser address bar.')
}, },
startBuildRun() { startBuildRun() {
build.isCustomSelection = false; build.isCustomSelection = false;

View File

@@ -16,11 +16,8 @@ const level = {
if (level.levelsCleared === 0) { //this code only runs on the first level if (level.levelsCleared === 0) { //this code only runs on the first level
// game.enableConstructMode() //used to build maps in testing mode // game.enableConstructMode() //used to build maps in testing mode
// level.difficultyIncrease(9) // level.difficultyIncrease(9)
// b.giveGuns("foam")
// mech.setField("time dilation field") // mech.setField("time dilation field")
// b.giveMod("necrophoresis"); // b.giveMod("many worlds");
// b.giveMod("impact shear");
// b.giveMod("foam-bot");
// b.giveGuns("neutron bomb") // b.giveGuns("neutron bomb")
// b.giveGuns("foam") // b.giveGuns("foam")
// mech.setField("pilot wave") // mech.setField("pilot wave")
@@ -162,10 +159,11 @@ const level = {
// spawn.bomberBoss(2900, -500) // spawn.bomberBoss(2900, -500)
// spawn.shooterBoss(1200, -500) // spawn.shooterBoss(1200, -500)
spawn.spinner(1200, -500, 40) // spawn.starter(2500, -40, 40)
// spawn.stabber(1600, -500) // spawn.stabber(1600, -500)
// spawn.cellBossCulture(1600, -500) // spawn.cellBossCulture(1600, -500)
// spawn.shooter(1600, -500) // spawn.shooter(1600, -500)
spawn.focuser(1600, -500)
// spawn.shield(mob[mob.length - 1], 1200, -500, 1); // spawn.shield(mob[mob.length - 1], 1200, -500, 1);
// spawn.nodeBoss(1200, -500, "spiker") // spawn.nodeBoss(1200, -500, "spiker")

View File

@@ -507,7 +507,7 @@ const mobs = {
}, },
springAttack() { springAttack() {
// set new values of the ends of the spring constraints // set new values of the ends of the spring constraints
if (this.seePlayer.recall) { if (this.seePlayer.recall && Matter.Query.ray(map, this.position, player.position).length === 0) {
if (!(game.cycle % (this.seePlayerFreq * 2))) { if (!(game.cycle % (this.seePlayerFreq * 2))) {
this.springTarget.x = this.seePlayer.position.x; this.springTarget.x = this.seePlayer.position.x;
this.springTarget.y = this.seePlayer.position.y; this.springTarget.y = this.seePlayer.position.y;
@@ -850,7 +850,6 @@ const mobs = {
if (!(game.cycle % this.seePlayerFreq)) { if (!(game.cycle % this.seePlayerFreq)) {
this.fireDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position)); this.fireDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position));
this.fireDir.y -= Math.abs(this.seePlayer.position.x - this.position.x) / 1600; //gives the bullet an arc this.fireDir.y -= Math.abs(this.seePlayer.position.x - this.position.x) / 1600; //gives the bullet an arc
this.fireAngle = Math.atan2(this.fireDir.y, this.fireDir.x);
} }
//rotate towards fireAngle //rotate towards fireAngle
const angle = this.angle + Math.PI / 2; const angle = this.angle + Math.PI / 2;
@@ -885,6 +884,52 @@ const mobs = {
// } // }
} }
}, },
launch() {
if (!mech.isBodiesAsleep) {
const setNoseShape = () => {
const mag = this.radius + this.radius * this.noseLength;
this.vertices[1].x = this.position.x + Math.cos(this.angle) * mag;
this.vertices[1].y = this.position.y + Math.sin(this.angle) * mag;
};
//throw a mob/bullet at player
if (this.seePlayer.recall) {
//set direction to turn to fire
if (!(game.cycle % this.seePlayerFreq)) {
this.fireDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position));
}
//rotate towards fireAngle
const angle = this.angle + Math.PI / 2;
c = Math.cos(angle) * this.fireDir.x + Math.sin(angle) * this.fireDir.y;
const threshold = 0.1;
if (c > threshold) {
this.torque += 0.0000045 * this.inertia;
} else if (c < -threshold) {
this.torque -= 0.0000045 * this.inertia;
} else if (this.noseLength > 1.5) {
//fire
spawn.seeker(this.vertices[1].x, this.vertices[1].y, 5 + Math.ceil(this.radius / 15), 5);
const v = 15;
Matter.Body.setVelocity(mob[mob.length - 1], {
x: this.velocity.x + this.fireDir.x * v + Math.random(),
y: this.velocity.y + this.fireDir.y * v + Math.random()
});
this.noseLength = 0;
// recoil
this.force.x -= 0.005 * this.fireDir.x * this.mass;
this.force.y -= 0.005 * this.fireDir.y * this.mass;
}
if (this.noseLength < 1.5) this.noseLength += this.fireFreq;
setNoseShape();
} else if (this.noseLength > 0.1) {
this.noseLength -= this.fireFreq / 2;
setNoseShape();
}
// else if (this.noseLength < -0.1) {
// this.noseLength += this.fireFreq / 4;
// setNoseShape();
// }
}
},
turnToFacePlayer() { turnToFacePlayer() {
//turn to face player //turn to face player
const dx = player.position.x - this.position.x; const dx = player.position.x - this.position.x;

View File

@@ -363,6 +363,7 @@ const mech = {
if (b.isModImmortal) { //if player has the immortality buff, spawn on the same level with randomized stats if (b.isModImmortal) { //if player has the immortality buff, spawn on the same level with randomized stats
spawn.setSpawnList(); //new mob types spawn.setSpawnList(); //new mob types
game.clearNow = true; //triggers a map reset game.clearNow = true; //triggers a map reset
powerUps.reroll.rerolls = Math.floor(Math.random() * Math.random() * 8)
//count mods //count mods
let totalMods = 0; let totalMods = 0;
@@ -380,6 +381,7 @@ const mech = {
b.mods[i].name !== "Born rule" && b.mods[i].name !== "Born rule" &&
b.mods[i].name !== "determinism" && b.mods[i].name !== "determinism" &&
b.mods[i].name !== "reallocation" && b.mods[i].name !== "reallocation" &&
b.mods[i].name !== "many worlds" &&
b.mods[i].allowed() b.mods[i].allowed()
) options.push(i); ) options.push(i);
} }
@@ -1045,7 +1047,7 @@ const mech = {
} }
if (mech.energy > mech.maxEnergy) mech.energy = mech.maxEnergy; if (mech.energy > mech.maxEnergy) mech.energy = mech.maxEnergy;
if (b.modBlockDmg) { if (b.modBlockDmg && mech.fieldUpgrades[mech.fieldMode].name === "standing wave harmonics") {
who.damage(b.modBlockDmg) who.damage(b.modBlockDmg)
//draw electricity //draw electricity
const step = 40 const step = 40
@@ -1087,7 +1089,7 @@ const mech = {
}); });
} }
} else { } else {
if (b.isModStunField) mobs.statusStun(who, b.isModStunField) if (b.isModStunField && mech.fieldUpgrades[mech.fieldMode].name === "perfect diamagnetism") mobs.statusStun(who, b.isModStunField)
// mobs.statusSlow(who, b.isModStunField) // mobs.statusSlow(who, b.isModStunField)
const massRoot = Math.sqrt(Math.max(0.15, who.mass)); // masses above 12 can start to overcome the push back const massRoot = Math.sqrt(Math.max(0.15, who.mass)); // masses above 12 can start to overcome the push back
Matter.Body.setVelocity(who, { Matter.Body.setVelocity(who, {
@@ -1434,7 +1436,7 @@ const mech = {
}, },
{ {
name: "negative mass field", name: "negative mass field",
description: "use <strong class='color-f'>energy</strong> to nullify &nbsp; <strong style='letter-spacing: 12px;'>gravity</strong><br>reduce <strong>harm</strong> by <strong>80%</strong> while field is active", //<br><strong>launch</strong> larger blocks at much higher speeds description: "use <strong class='color-f'>energy</strong> to nullify &nbsp; <strong style='letter-spacing: 12px;'>gravity</strong><br>reduce <strong>harm</strong> by <strong>80%</strong> while field is active",
fieldDrawRadius: 0, fieldDrawRadius: 0,
isEasyToAim: true, isEasyToAim: true,
effect: () => { effect: () => {
@@ -1569,10 +1571,11 @@ const mech = {
}, },
{ {
name: "plasma torch", name: "plasma torch",
description: "use <strong class='color-f'>energy</strong> to emit <strong class='color-d'>damaging</strong> plasma<br><em>effective at close range</em>", description: "use <strong class='color-f'>energy</strong> to emit <strong class='color-d'>damaging</strong> plasma<br>reduce <strong>harm</strong> by <strong>33%</strong>",
isEasyToAim: false, isEasyToAim: false,
effect: () => { effect: () => {
mech.fieldMeterColor = "#f0f" mech.fieldMeterColor = "#f0f"
mech.fieldDamageResistance = 0.67; //reduce harm by 33%
mech.hold = function () { mech.hold = function () {
if (mech.isHolding) { if (mech.isHolding) {
@@ -1582,7 +1585,7 @@ const mech = {
} else if ((keys[32] || game.mouseDownRight) && mech.fieldCDcycle < mech.cycle) { //not hold but field button is pressed } else if ((keys[32] || game.mouseDownRight) && mech.fieldCDcycle < mech.cycle) { //not hold but field button is pressed
mech.grabPowerUp(); mech.grabPowerUp();
mech.lookForPickUp(); mech.lookForPickUp();
const DRAIN = 0.00065 const DRAIN = 0.0006
if (mech.energy > DRAIN) { if (mech.energy > DRAIN) {
mech.energy -= DRAIN; mech.energy -= DRAIN;
if (mech.energy < 0) { if (mech.energy < 0) {
@@ -1666,8 +1669,12 @@ const mech = {
best.who.locatePlayer(); best.who.locatePlayer();
//push mobs away //push mobs away
const force = Vector.mult(Vector.normalise(Vector.sub(mech.pos, path[1])), -0.02 * Math.sqrt(best.who.mass)) const force = Vector.mult(Vector.normalise(Vector.sub(mech.pos, path[1])), -0.01 * Math.min(5, best.who.mass))
Matter.Body.applyForce(best.who, path[1], force) Matter.Body.applyForce(best.who, path[1], force)
Matter.Body.setVelocity(best.who, { //friction
x: best.who.velocity.x * 0.6,
y: best.who.velocity.y * 0.6
});
// const angle = Math.atan2(player.position.y - best.who.position.y, player.position.x - best.who.position.x); // const angle = Math.atan2(player.position.y - best.who.position.y, player.position.x - best.who.position.x);
// const mass = Math.min(Math.sqrt(best.who.mass), 6); // const mass = Math.min(Math.sqrt(best.who.mass), 6);
// Matter.Body.setVelocity(best.who, { // Matter.Body.setVelocity(best.who, {
@@ -1685,7 +1692,7 @@ const mech = {
}); });
} else if (!best.who.isStatic) { } else if (!best.who.isStatic) {
//push blocks away //push blocks away
const force = Vector.mult(Vector.normalise(Vector.sub(mech.pos, path[1])), -0.006 * Math.sqrt(Math.sqrt(best.who.mass))) const force = Vector.mult(Vector.normalise(Vector.sub(mech.pos, path[1])), -0.007 * Math.sqrt(Math.sqrt(best.who.mass)))
Matter.Body.applyForce(best.who, path[1], force) Matter.Body.applyForce(best.who, path[1], force)
} }
} }

View File

@@ -21,6 +21,10 @@ const powerUps = {
powerUps.endDraft(); powerUps.endDraft();
}, },
endDraft() { endDraft() {
if (b.manyWorlds) {
powerUps.spawn(mech.pos.x, mech.pos.y, "reroll");
if (Math.random() < b.modBayesian) powerUps.spawn(mech.pos.x, mech.pos.y, "reroll");
}
document.body.style.cursor = "none"; document.body.style.cursor = "none";
document.getElementById("choose-grid").style.display = "none" document.getElementById("choose-grid").style.display = "none"
document.getElementById("choose-background").style.display = "none" document.getElementById("choose-background").style.display = "none"
@@ -162,7 +166,7 @@ const powerUps = {
let choice2 = -1 let choice2 = -1
let choice3 = -1 let choice3 = -1
if (choice1 > -1) { if (choice1 > -1) {
let text = `<div class='cancel' onclick='powerUps.endDraft("field")'>✕</div><h3 style = 'color:#fff; text-align:left; margin: 0px;'>choose a field</h3>` let text = `<div class='cancel' onclick='powerUps.endDraft()'>✕</div><h3 style = 'color:#fff; text-align:left; margin: 0px;'>choose a field</h3>`
text += `<div class="choose-grid-module" onclick="powerUps.choose('field',${choice1})"><div class="grid-title"><div class="circle-grid field"></div> &nbsp; ${mech.fieldUpgrades[choice1].name}</div> ${mech.fieldUpgrades[choice1].description}</div>` text += `<div class="choose-grid-module" onclick="powerUps.choose('field',${choice1})"><div class="grid-title"><div class="circle-grid field"></div> &nbsp; ${mech.fieldUpgrades[choice1].name}</div> ${mech.fieldUpgrades[choice1].description}</div>`
if (!b.isModDeterminism) { if (!b.isModDeterminism) {
choice2 = pick(mech.fieldUpgrades, choice1) choice2 = pick(mech.fieldUpgrades, choice1)
@@ -207,7 +211,7 @@ const powerUps = {
let choice2 = -1 let choice2 = -1
let choice3 = -1 let choice3 = -1
if (choice1 > -1) { if (choice1 > -1) {
let text = `<div class='cancel' onclick='powerUps.endDraft("mod")'>✕</div><h3 style = 'color:#fff; text-align:left; margin: 0px;'>choose a mod</h3>` let text = `<div class='cancel' onclick='powerUps.endDraft()'>✕</div><h3 style = 'color:#fff; text-align:left; margin: 0px;'>choose a mod</h3>`
text += `<div class="choose-grid-module" onclick="powerUps.choose('mod',${choice1})"><div class="grid-title"><div class="circle-grid mod"></div> &nbsp; ${b.mods[choice1].name}</div> ${b.mods[choice1].description}</div>` text += `<div class="choose-grid-module" onclick="powerUps.choose('mod',${choice1})"><div class="grid-title"><div class="circle-grid mod"></div> &nbsp; ${b.mods[choice1].name}</div> ${b.mods[choice1].description}</div>`
if (!b.isModDeterminism) { if (!b.isModDeterminism) {
choice2 = pick(choice1) choice2 = pick(choice1)
@@ -249,7 +253,7 @@ const powerUps = {
let choice2 = -1 let choice2 = -1
let choice3 = -1 let choice3 = -1
if (choice1 > -1) { if (choice1 > -1) {
let text = `<div class='cancel' onclick='powerUps.endDraft("gun")'>✕</div><h3 style = 'color:#fff; text-align:left; margin: 0px;'>choose a gun</h3>` let text = `<div class='cancel' onclick='powerUps.endDraft()'>✕</div><h3 style = 'color:#fff; text-align:left; margin: 0px;'>choose a gun</h3>`
text += `<div class="choose-grid-module" onclick="powerUps.choose('gun',${choice1})"><div class="grid-title"><div class="circle-grid gun"></div> &nbsp; ${b.guns[choice1].name}</div> ${b.guns[choice1].description}</div>` text += `<div class="choose-grid-module" onclick="powerUps.choose('gun',${choice1})"><div class="grid-title"><div class="circle-grid gun"></div> &nbsp; ${b.guns[choice1].name}</div> ${b.guns[choice1].description}</div>`
if (!b.isModDeterminism) { if (!b.isModDeterminism) {
choice2 = pick(b.guns, choice1) choice2 = pick(b.guns, choice1)
@@ -312,7 +316,7 @@ const powerUps = {
if (Math.random() < b.modBayesian) powerUps.spawn(x, y, "field"); if (Math.random() < b.modBayesian) powerUps.spawn(x, y, "field");
return; return;
} }
if (Math.random() < 0.01) { if (Math.random() < 0.005) {
powerUps.spawn(x, y, "reroll"); powerUps.spawn(x, y, "reroll");
if (Math.random() < b.modBayesian) powerUps.spawn(x, y, "reroll"); if (Math.random() < b.modBayesian) powerUps.spawn(x, y, "reroll");
return; return;
@@ -352,7 +356,7 @@ const powerUps = {
} }
}, },
chooseRandomPowerUp(x, y) { //100% chance to drop a random power up //used in spawn.debris chooseRandomPowerUp(x, y) { //100% chance to drop a random power up //used in spawn.debris
if (Math.random() < 0.02) { if (Math.random() < 0.05) {
powerUps.spawn(x, y, "reroll"); powerUps.spawn(x, y, "reroll");
} else if (Math.random() < 0.5) { } else if (Math.random() < 0.5) {
powerUps.spawn(x, y, "heal", false); powerUps.spawn(x, y, "heal", false);

View File

@@ -2,13 +2,14 @@
const spawn = { const spawn = {
pickList: ["starter", "starter"], pickList: ["starter", "starter"],
fullPickList: [ fullPickList: [
"shooter", "shooter", "shooter", "shooter", "shooter", "shooter", "shooter", "shooter", "shooter",
"hopper", "hopper", "hopper", "hopper", "hopper", "hopper", "hopper", "hopper",
"chaser", "chaser", "chaser", "chaser", "chaser", "chaser",
"striker", "striker", "striker", "striker",
"laser", "laser", "laser", "laser",
"exploder", "exploder", "exploder", "exploder",
"stabber", "stabber", "stabber", "stabber",
"launcher", "launcher",
"spinner", "spinner",
"grower", "grower",
"springer", "springer",
@@ -19,7 +20,7 @@ const spawn = {
"ghoster", "ghoster",
"sneaker", "sneaker",
], ],
allowedBossList: ["chaser", "spinner", "striker", "springer", "laser", "focuser", "beamer", "exploder", "spawner", "shooter", "stabber"], allowedBossList: ["chaser", "spinner", "striker", "springer", "laser", "focuser", "beamer", "exploder", "spawner", "shooter", "launcher", "stabber"],
setSpawnList() { //this is run at the start of each new level to determine the possible mobs for the level setSpawnList() { //this is run at the start of each new level to determine the possible mobs for the level
//each level has 2 mobs: one new mob and one from the last level //each level has 2 mobs: one new mob and one from the last level
spawn.pickList.splice(0, 1); spawn.pickList.splice(0, 1);
@@ -845,30 +846,30 @@ const spawn = {
if (!mech.isBodiesAsleep) { if (!mech.isBodiesAsleep) {
this.seePlayerByLookingAt(); this.seePlayerByLookingAt();
this.checkStatus(); this.checkStatus();
this.attraction();
const dist2 = this.distanceToPlayer2(); const dist2 = this.distanceToPlayer2();
//laser Tracking //laser Tracking
if (this.seePlayer.yes && dist2 < 4000000 && !mech.isStealth) { if (this.seePlayer.yes && dist2 < 4000000) {
this.attraction();
const rangeWidth = 2000; //this is sqrt of 4000000 from above if() const rangeWidth = 2000; //this is sqrt of 4000000 from above if()
//targeting laser will slowly move from the mob to the player's position //targeting laser will slowly move from the mob to the player's position
this.laserPos = Vector.add(this.laserPos, Vector.mult(Vector.sub(player.position, this.laserPos), 0.1)); this.laserPos = Vector.add(this.laserPos, Vector.mult(Vector.sub(player.position, this.laserPos), 0.1));
let targetDist = Vector.magnitude(Vector.sub(this.laserPos, mech.pos)); let targetDist = Vector.magnitude(Vector.sub(this.laserPos, mech.pos));
const r = 10; const r = 12;
ctx.beginPath(); ctx.beginPath();
ctx.moveTo(this.position.x, this.position.y); ctx.moveTo(this.position.x, this.position.y);
if (targetDist < r + 15) { if (targetDist < r + 16) {
targetDist = r + 10; targetDist = r + 10;
//charge at player //charge at player
const forceMag = this.accelMag * 40 * this.mass; const forceMag = this.accelMag * 30 * this.mass;
const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x); const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x);
this.force.x += forceMag * Math.cos(angle); this.force.x += forceMag * Math.cos(angle);
this.force.y += forceMag * Math.sin(angle); this.force.y += forceMag * Math.sin(angle);
} else { } else {
//high friction if can't lock onto player //high friction if can't lock onto player
Matter.Body.setVelocity(this, { // Matter.Body.setVelocity(this, {
x: this.velocity.x * 0.96, // x: this.velocity.x * 0.98,
y: this.velocity.y * 0.96 // y: this.velocity.y * 0.98
}); // });
} }
if (dist2 > 80000) { if (dist2 > 80000) {
const laserWidth = 0.002; const laserWidth = 0.002;
@@ -1436,6 +1437,58 @@ const spawn = {
this.timeLimit(); this.timeLimit();
}; };
}, },
launcher(x, y, radius = 25 + Math.ceil(Math.random() * 50)) {
mobs.spawn(x, y, 3, radius, "rgb(150,150,255)");
let me = mob[mob.length - 1];
me.vertices = Matter.Vertices.clockwiseSort(Matter.Vertices.rotate(me.vertices, Math.PI, me.position)); //make the pointy side of triangle the front
me.isVerticesChange = true
// Matter.Body.rotate(me, Math.PI)
me.memory = 120;
me.fireFreq = 0.006 + Math.random() * 0.003;
me.noseLength = 0;
me.fireAngle = 0;
me.accelMag = 0.0005 * game.accelScale;
me.frictionAir = 0.05;
me.lookTorque = 0.0000028 * (Math.random() > 0.5 ? -1 : 1);
me.fireDir = {
x: 0,
y: 0
};
me.onDeath = function () { //helps collisions functions work better after vertex have been changed
// this.vertices = Matter.Vertices.hull(Matter.Vertices.clockwiseSort(this.vertices))
}
// spawn.shield(me, x, y);
me.do = function () {
this.seePlayerByLookingAt();
this.checkStatus();
this.launch();
};
},
seeker(x, y, radius = 6, sides = 0) {
//bullets
mobs.spawn(x, y, sides, radius, "rgb(0,0,255)");
let me = mob[mob.length - 1];
me.stroke = "transparent";
me.onHit = function () {
this.explode(this.mass * 10);
};
Matter.Body.setDensity(me, 0.00005); //normal is 0.001
me.timeLeft = 420;
me.accelMag = 0.0004 * game.accelScale;
me.frictionAir = 0.035;
me.restitution = 0.5;
me.leaveBody = false;
me.dropPowerUp = false;
me.showHealthBar = false;
me.collisionFilter.category = cat.mobBullet;
me.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet;
me.do = function () {
this.seePlayerCheck();
this.attraction();
this.timeLimit();
};
},
spawner(x, y, radius = 55 + Math.ceil(Math.random() * 50)) { spawner(x, y, radius = 55 + Math.ceil(Math.random() * 50)) {
mobs.spawn(x, y, 4, radius, "rgb(255,150,0)"); mobs.spawn(x, y, 4, radius, "rgb(255,150,0)");
let me = mob[mob.length - 1]; let me = mob[mob.length - 1];

View File

@@ -466,6 +466,11 @@ em {
letter-spacing: 1px; letter-spacing: 1px;
} }
.color-r {
color: #f7b;
letter-spacing: 1px;
}
.faded { .faded {
opacity: 0.7; opacity: 0.7;
font-size: 90%; font-size: 90%;
@@ -511,7 +516,6 @@ em {
} }
.reroll { .reroll {
/* #f84 #f99*/ /* #f84 #f99*/
background: #f7b; background: #f7b;
} }

View File

@@ -1,20 +1,21 @@
foam bullets are faster, smaller, shrink slower, stick to mobs better mod - many worlds: spawn a reroll after choosing (or canceling) a power up
foam can now stick to shielded mobs, but shrinks faster new mob type - launcher: similar to the shooter, but fires bullets that chase you
mod: foam-bots plasma torch - reduces harm to player by 1/3 and has more reliable stopping power against charging mobs
explosions and neutron bomb do 50% less damage through walls
drone bullets bounce off mobs more predictably
************** TODO - n-gon ************** ************** TODO - n-gon **************
power up reroll what about a neutron bomb mod, that cause the bomb to activate right after you fire and slowly move forward with no gravity
color yellow?
Drop a reroll when the player exits the selection screen without picking one of the choices
redblobgames.com/articles/visibility
https://github.com/Silverwolf90/2d-visibility/tree/master/src
could apply to explosions, neutron bomb, player LOS
sticking bullets don't always gain the correct speed from mobs after they die sticking bullets don't always gain the correct speed from mobs after they die
mod - frozen mobs take +33% damage
mod heal to full at the end of each level
heal mods no longer drop?
possible names for mods 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. Hypergolic - A hypergolic propellant combination used in a rocket engine is one whose components spontaneously ignite when they come into contact with each other.
@@ -24,19 +25,6 @@ have a mob apply a positive status effect on other mobs,
damage bonus, but how? damage bonus, but how?
possible balance issues 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
?highlight map/body mouse is over and be able to remove it?
display current output text in a box
live update it
boss levels - small levels just a boss, and maybe a few mobs boss levels - small levels just a boss, and maybe a few mobs
boss level for timeSkipBoss because of game instability for boss on normal levels boss level for timeSkipBoss because of game instability for boss on normal levels
this might not fix issues this might not fix issues
@@ -65,10 +53,6 @@ lore - a robot (the player) gains self awareness
the next level is the final level the next level is the final level
when you die with Quantum Immortality there is a chance of lore text when you die with Quantum Immortality there is a chance of lore text
scrap drops that can be used to buy things in a shop
scrap could be yellow
shop could appear every 4 levels
mob - stuns, or slows player mob - stuns, or slows player
boss mob - let it die multiple times and come back to life boss mob - let it die multiple times and come back to life
@@ -90,16 +74,11 @@ uranium reactor core
add player Scent Trails for mob navigation add player Scent Trails for mob navigation
https://abitawake.com/news/articles/enemy-ai-chasing-a-player-without-navigation2d-or-a-star-pathfinding https://abitawake.com/news/articles/enemy-ai-chasing-a-player-without-navigation2d-or-a-star-pathfinding
mod - killing a stunned mob gives something
ammo or heal power up?
mod - scale squirrel cage rotor with current energy mod - scale squirrel cage rotor with current energy
is variable speed going to be hard to deal with? is variable speed going to be hard to deal with?
mod - you can no longer see your current health mod - you can no longer see your current health
mob sniper - targeting laser, then a high speed, no gravity bullet
mod - increase laser bot range, and reduce energy drain mod - increase laser bot range, and reduce energy drain
mod - mines become a turret that fires nails mod - mines become a turret that fires nails