added laser bot

This commit is contained in:
landgreen
2019-12-07 13:38:39 -08:00
committed by GitHub
parent 53b7cf7bc6
commit 7508b52d91
9 changed files with 9615 additions and 9596 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,233 +1,233 @@
//matter.js ***********************************************************
// module aliases
const Engine = Matter.Engine,
World = Matter.World,
Events = Matter.Events,
Composites = Matter.Composites,
Composite = Matter.Composite,
Constraint = Matter.Constraint,
Vertices = Matter.Vertices,
Query = Matter.Query,
Body = Matter.Body,
Bodies = Matter.Bodies;
// create an engine
const engine = Engine.create();
engine.world.gravity.scale = 0; //turn off gravity (it's added back in later)
// engine.velocityIterations = 100
// engine.positionIterations = 100
// engine.enableSleeping = true
// matter events *********************************************************
//************************************************************************
//************************************************************************
//************************************************************************
function playerOnGroundCheck(event) {
//runs on collisions events
function enter() {
mech.numTouching++;
if (!mech.onGround) mech.enterLand();
}
const pairs = event.pairs;
for (let i = 0, j = pairs.length; i != j; ++i) {
let pair = pairs[i];
if (pair.bodyA === jumpSensor) {
mech.standingOn = pair.bodyB; //keeping track to correctly provide recoil on jump
if (mech.standingOn.alive !== true) enter();
} else if (pair.bodyB === jumpSensor) {
mech.standingOn = pair.bodyA; //keeping track to correctly provide recoil on jump
if (mech.standingOn.alive !== true) enter();
}
}
mech.numTouching = 0;
}
function playerOffGroundCheck(event) {
//runs on collisions events
function enter() {
if (mech.onGround && mech.numTouching === 0) mech.enterAir();
}
const pairs = event.pairs;
for (let i = 0, j = pairs.length; i != j; ++i) {
if (pairs[i].bodyA === jumpSensor) {
enter();
} else if (pairs[i].bodyB === jumpSensor) {
enter();
}
}
}
function playerHeadCheck(event) {
//runs on collisions events
if (mech.crouch) {
mech.isHeadClear = true;
const pairs = event.pairs;
for (let i = 0, j = pairs.length; i != j; ++i) {
if (pairs[i].bodyA === headSensor) {
mech.isHeadClear = false;
} else if (pairs[i].bodyB === headSensor) {
mech.isHeadClear = false;
}
}
}
}
function mobCollisionChecks(event) {
const pairs = event.pairs;
for (let i = 0, j = pairs.length; i != j; i++) {
//body + player collision
if (game.isBodyDamage && mech.damageImmune < mech.cycle) {
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, speedThreshold = 12, massThreshold = 2) {
if (obj.classType === "body" && obj.speed > speedThreshold && obj.mass > massThreshold) { //dmg from hitting a body
const v = Matter.Vector.magnitude(Matter.Vector.sub(player.velocity, obj.velocity));
if (v > speedThreshold) {
mech.damageImmune = mech.cycle + 30; //player is immune to collision damage for 30 cycles
let dmg = Math.sqrt((v - speedThreshold + 0.1) * (obj.mass - massThreshold)) * 0.01;
dmg = Math.min(Math.max(dmg, 0.02), 0.15);
mech.damage(dmg);
game.drawList.push({ //add dmg to draw queue
x: pairs[i].activeContacts[0].vertex.x,
y: pairs[i].activeContacts[0].vertex.y,
radius: dmg * 500,
color: game.mobDmgColor,
time: game.drawTime
});
return;
}
}
// else if (obj.isStatic && player.speed > speedThreshold * 2) { //falling dmg / hitting map dmg
// mech.damageImmune = mech.cycle + 30;
// console.log(player.speed)
// let dmg = Math.min(Math.max(player.speed * 0.001, 0.02), 0.2);
// mech.damage(dmg);
// game.drawList.push({
// //add dmg to draw queue
// x: pairs[i].activeContacts[0].vertex.x,
// y: pairs[i].activeContacts[0].vertex.y,
// radius: dmg * 500,
// color: game.mobDmgColor,
// time: game.drawTime
// });
// return;
// }
}
//mob + (player,bullet,body) collisions
for (let k = 0; k < mob.length; k++) {
if (mob[k].alive && mech.alive) {
if (pairs[i].bodyA === mob[k]) {
collideMob(pairs[i].bodyB);
break;
} else if (pairs[i].bodyB === mob[k]) {
collideMob(pairs[i].bodyA);
break;
}
function collideMob(obj) {
//player + mob collision
if (obj === playerBody || obj === playerHead) {
if (mech.damageImmune < mech.cycle) {
mech.damageImmune = mech.cycle + 30; //player is immune to collision damage for 30 cycles
mob[k].foundPlayer();
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
mech.damage(dmg);
if (mob[k].onHit) mob[k].onHit(k);
if (b.modAnnihilation && mob[k].dropPowerUp) {
mob[k].death();
game.drawList.push({
//add dmg to draw queue
x: pairs[i].activeContacts[0].vertex.x,
y: pairs[i].activeContacts[0].vertex.y,
radius: dmg * 2000,
color: "rgba(255,0,255,0.2)",
time: game.drawTime
});
} else {
game.drawList.push({
//add dmg to draw queue
x: pairs[i].activeContacts[0].vertex.x,
y: pairs[i].activeContacts[0].vertex.y,
radius: dmg * 500,
color: game.mobDmgColor,
time: game.drawTime
});
}
}
//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, {
x: player.velocity.x + 8 * Math.cos(angle),
y: player.velocity.y + 8 * Math.sin(angle)
});
Matter.Body.setVelocity(mob[k], {
x: mob[k].velocity.x - 8 * Math.cos(angle),
y: mob[k].velocity.y - 8 * Math.sin(angle)
});
return;
}
//mob + bullet collisions
if (obj.classType === "bullet" && obj.speed > obj.minDmgSpeed) {
// const dmg = b.dmgScale * (obj.dmg + 0.15 * obj.mass * Matter.Vector.magnitude(Matter.Vector.sub(mob[k].velocity, obj.velocity)));
let dmg = b.dmgScale * (obj.dmg + b.modExtraDmg + 0.15 * obj.mass * Matter.Vector.magnitude(Matter.Vector.sub(mob[k].velocity, obj.velocity)))
if (b.modIsCrit && !mob[k].seePlayer.recall) dmg *= 5
mob[k].foundPlayer();
mob[k].damage(dmg);
obj.onDmg(); //some bullets do actions when they hits things, like despawn
game.drawList.push({
//add dmg to draw queue
x: pairs[i].activeContacts[0].vertex.x,
y: pairs[i].activeContacts[0].vertex.y,
// radius: Math.sqrt(dmg) * 40,
radius: Math.log(2 * dmg + 1.1) * 40,
color: game.playerDmgColor,
time: game.drawTime
});
return;
}
//mob + body collisions
if (obj.classType === "body" && obj.speed > 5) {
const v = Matter.Vector.magnitude(Matter.Vector.sub(mob[k].velocity, obj.velocity));
if (v > 8) {
let dmg = b.dmgScale * v * Math.sqrt(obj.mass) * 0.05;
mob[k].damage(dmg);
if (mob[k].distanceToPlayer2() < 1000000) mob[k].foundPlayer();
game.drawList.push({
//add dmg to draw queue
x: pairs[i].activeContacts[0].vertex.x,
y: pairs[i].activeContacts[0].vertex.y,
radius: Math.sqrt(dmg) * 40,
color: game.playerDmgColor,
time: game.drawTime
});
return;
}
}
}
}
}
}
}
//determine if player is on the ground
Events.on(engine, "collisionStart", function (event) {
playerOnGroundCheck(event);
playerHeadCheck(event);
mobCollisionChecks(event);
});
Events.on(engine, "collisionActive", function (event) {
playerOnGroundCheck(event);
playerHeadCheck(event);
});
Events.on(engine, "collisionEnd", function (event) {
playerOffGroundCheck(event);
//matter.js ***********************************************************
// module aliases
const Engine = Matter.Engine,
World = Matter.World,
Events = Matter.Events,
Composites = Matter.Composites,
Composite = Matter.Composite,
Constraint = Matter.Constraint,
Vertices = Matter.Vertices,
Query = Matter.Query,
Body = Matter.Body,
Bodies = Matter.Bodies;
// create an engine
const engine = Engine.create();
engine.world.gravity.scale = 0; //turn off gravity (it's added back in later)
// engine.velocityIterations = 100
// engine.positionIterations = 100
// engine.enableSleeping = true
// matter events *********************************************************
//************************************************************************
//************************************************************************
//************************************************************************
function playerOnGroundCheck(event) {
//runs on collisions events
function enter() {
mech.numTouching++;
if (!mech.onGround) mech.enterLand();
}
const pairs = event.pairs;
for (let i = 0, j = pairs.length; i != j; ++i) {
let pair = pairs[i];
if (pair.bodyA === jumpSensor) {
mech.standingOn = pair.bodyB; //keeping track to correctly provide recoil on jump
if (mech.standingOn.alive !== true) enter();
} else if (pair.bodyB === jumpSensor) {
mech.standingOn = pair.bodyA; //keeping track to correctly provide recoil on jump
if (mech.standingOn.alive !== true) enter();
}
}
mech.numTouching = 0;
}
function playerOffGroundCheck(event) {
//runs on collisions events
function enter() {
if (mech.onGround && mech.numTouching === 0) mech.enterAir();
}
const pairs = event.pairs;
for (let i = 0, j = pairs.length; i != j; ++i) {
if (pairs[i].bodyA === jumpSensor) {
enter();
} else if (pairs[i].bodyB === jumpSensor) {
enter();
}
}
}
function playerHeadCheck(event) {
//runs on collisions events
if (mech.crouch) {
mech.isHeadClear = true;
const pairs = event.pairs;
for (let i = 0, j = pairs.length; i != j; ++i) {
if (pairs[i].bodyA === headSensor) {
mech.isHeadClear = false;
} else if (pairs[i].bodyB === headSensor) {
mech.isHeadClear = false;
}
}
}
}
function mobCollisionChecks(event) {
const pairs = event.pairs;
for (let i = 0, j = pairs.length; i != j; i++) {
//body + player collision
if (game.isBodyDamage && mech.damageImmune < mech.cycle) {
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, speedThreshold = 12, massThreshold = 2) {
if (obj.classType === "body" && obj.speed > speedThreshold && obj.mass > massThreshold) { //dmg from hitting a body
const v = Matter.Vector.magnitude(Matter.Vector.sub(player.velocity, obj.velocity));
if (v > speedThreshold) {
mech.damageImmune = mech.cycle + 30; //player is immune to collision damage for 30 cycles
let dmg = Math.sqrt((v - speedThreshold + 0.1) * (obj.mass - massThreshold)) * 0.01;
dmg = Math.min(Math.max(dmg, 0.02), 0.15);
mech.damage(dmg);
game.drawList.push({ //add dmg to draw queue
x: pairs[i].activeContacts[0].vertex.x,
y: pairs[i].activeContacts[0].vertex.y,
radius: dmg * 500,
color: game.mobDmgColor,
time: game.drawTime
});
return;
}
}
// else if (obj.isStatic && player.speed > speedThreshold * 2) { //falling dmg / hitting map dmg
// mech.damageImmune = mech.cycle + 30;
// console.log(player.speed)
// let dmg = Math.min(Math.max(player.speed * 0.001, 0.02), 0.2);
// mech.damage(dmg);
// game.drawList.push({
// //add dmg to draw queue
// x: pairs[i].activeContacts[0].vertex.x,
// y: pairs[i].activeContacts[0].vertex.y,
// radius: dmg * 500,
// color: game.mobDmgColor,
// time: game.drawTime
// });
// return;
// }
}
//mob + (player,bullet,body) collisions
for (let k = 0; k < mob.length; k++) {
if (mob[k].alive && mech.alive) {
if (pairs[i].bodyA === mob[k]) {
collideMob(pairs[i].bodyB);
break;
} else if (pairs[i].bodyB === mob[k]) {
collideMob(pairs[i].bodyA);
break;
}
function collideMob(obj) {
//player + mob collision
if (obj === playerBody || obj === playerHead) {
if (mech.damageImmune < mech.cycle) {
mech.damageImmune = mech.cycle + 30; //player is immune to collision damage for 30 cycles
mob[k].foundPlayer();
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
mech.damage(dmg);
if (mob[k].onHit) mob[k].onHit(k);
if (b.modAnnihilation && mob[k].dropPowerUp) {
mob[k].death();
game.drawList.push({
//add dmg to draw queue
x: pairs[i].activeContacts[0].vertex.x,
y: pairs[i].activeContacts[0].vertex.y,
radius: dmg * 2000,
color: "rgba(255,0,255,0.2)",
time: game.drawTime
});
} else {
game.drawList.push({
//add dmg to draw queue
x: pairs[i].activeContacts[0].vertex.x,
y: pairs[i].activeContacts[0].vertex.y,
radius: dmg * 500,
color: game.mobDmgColor,
time: game.drawTime
});
}
}
//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, {
x: player.velocity.x + 8 * Math.cos(angle),
y: player.velocity.y + 8 * Math.sin(angle)
});
Matter.Body.setVelocity(mob[k], {
x: mob[k].velocity.x - 8 * Math.cos(angle),
y: mob[k].velocity.y - 8 * Math.sin(angle)
});
return;
}
//mob + bullet collisions
if (obj.classType === "bullet" && obj.speed > obj.minDmgSpeed) {
// const dmg = b.dmgScale * (obj.dmg + 0.15 * obj.mass * Matter.Vector.magnitude(Matter.Vector.sub(mob[k].velocity, obj.velocity)));
let dmg = b.dmgScale * (obj.dmg + b.modExtraDmg + 0.15 * obj.mass * Matter.Vector.magnitude(Matter.Vector.sub(mob[k].velocity, obj.velocity)))
if (b.modIsCrit && !mob[k].seePlayer.recall) dmg *= 5
mob[k].foundPlayer();
mob[k].damage(dmg);
obj.onDmg(); //some bullets do actions when they hits things, like despawn
game.drawList.push({
//add dmg to draw queue
x: pairs[i].activeContacts[0].vertex.x,
y: pairs[i].activeContacts[0].vertex.y,
// radius: Math.sqrt(dmg) * 40,
radius: Math.log(2 * dmg + 1.1) * 40,
color: game.playerDmgColor,
time: game.drawTime
});
return;
}
//mob + body collisions
if (obj.classType === "body" && obj.speed > 5) {
const v = Matter.Vector.magnitude(Matter.Vector.sub(mob[k].velocity, obj.velocity));
if (v > 8) {
let dmg = b.dmgScale * v * Math.sqrt(obj.mass) * 0.05;
mob[k].damage(dmg);
if (mob[k].distanceToPlayer2() < 1000000) mob[k].foundPlayer();
game.drawList.push({
//add dmg to draw queue
x: pairs[i].activeContacts[0].vertex.x,
y: pairs[i].activeContacts[0].vertex.y,
radius: Math.sqrt(dmg) * 40,
color: game.playerDmgColor,
time: game.drawTime
});
return;
}
}
}
}
}
}
}
//determine if player is on the ground
Events.on(engine, "collisionStart", function (event) {
playerOnGroundCheck(event);
playerHeadCheck(event);
mobCollisionChecks(event);
});
Events.on(engine, "collisionActive", function (event) {
playerOnGroundCheck(event);
playerHeadCheck(event);
});
Events.on(engine, "collisionEnd", function (event) {
playerOffGroundCheck(event);
});

2098
js/game.js

File diff suppressed because it is too large Load Diff

View File

@@ -1,347 +1,347 @@
"use strict";
/* TODO: *******************************************
*****************************************************
add builds with combinations of gun, field and mobs
use the pull down menu
dynamically generate html about fields, guns and mods
add grid check to improve queries over large body arrays
something about broad phase
having trouble with this, might give up
gun: like drones, but fast moving and short lived
dies after doing damage
gun: Spirit Bomb (singularity)
use charge up like rail gun
electricity graphics like plasma torch
suck in nearby mobs, power ups?, blocks?
sucked in stuff increase size
uses energy
mod: auto pick up guns, heals, ammo
use the same rule for drones
maybe give some other bonus too?
rework junk bot
it's behavior is too unpredictable
range is unclear
having the bullets last long after doing dmg isn't fun
we want a fun gun that acts like a melee weapon
atmosphere levels
large rotating fan that the player has to move through
give the user a rest, between combat
low combat
nonaggressive mobs
one mob attacking the passive mobs
more graphics
Boss levels
boss grows and spilt, if you don't kill it fast
sensor that locks you in after you enter the boss room
boss that eats other mobs and gains stats from them
chance to spawn on any level (past level 5)
boss that knows how to shoot (player) bullets that collide with player
overwrite custom engine collision bullet mob function.
add a key that player picks up and needs to set on the exit door to open it
make power ups keep moving to player if the pickup field is turned off before they get picked up
not sure how to do this without adding a constant check
animate new level spawn by having the map aspects randomly fly into place
new map with repeating endlessness
get ideas from Manifold Garden game
if falling, get teleported above the map
I tried it, but had trouble getting the camera to adjust to the teleportation
this can apply to blocks mobs, and power ups as well
field power up effects
field allows player to hold and throw living mobs
mod power ups ideas
double jump
bullet on mob damage effects
add to the array mob.do new mob behaviors
add a damage over time
add a freeze
give mobs more animal-like behaviors
like rain world
give mobs something to do when they don't see player
explore map
eat power ups
drop power up (if killed after eating one)
mobs some times aren't aggressive
when low on life or after taking a large hit
mobs can fight each other
this might be hard to code
isolated mobs try to group up.
game mechanics
mechanics that support the physics engine
add rope/constraint
get ideas from game: limbo / inside
environmental hazards
laser
lava
button / switch
door
fizzler
moving platform
map zones
water
low friction ground
bouncy ground
// collision info:
category mask
powerUp: 0x100000 0x100001
body: 0x010000 0x011111
player: 0x001000 0x010011
bullet: 0x000100 0x010011
mob: 0x000010 0x011111
mobBullet: 0x000010 0x011101
mobShield: 0x000010 0x001100
map: 0x000001 0x111111
*/
//build build grid display
const build = {
isShowingBuilds: false,
list: [],
choosePowerUp(who, index, type) {
//check if matching a current power up
for (let i = 0; i < build.list.length; i++) {
if (build.list[i].index === index && build.list[i].type === type) { //if already click, toggle off
build.list.splice(i, 1);
who.style.backgroundColor = "#fff"
return
}
}
//check if trying to get a second field
if (type === "field") {
for (let i = 0; i < build.list.length; i++) {
if (build.list[i].type === "field") { //if already click, toggle off
build.list[i].who.style.backgroundColor = "#fff"
build.list.splice(i, 1);
}
}
}
if (build.list.length < 5) { //add to build array
// who.style.border = "2px solid #333"
who.style.backgroundColor = "#919ba8" //"#868f9a"
build.list[build.list.length] = {
who: who,
index: index,
type: type
}
}
},
startBuildRun() {
spawn.setSpawnList();
spawn.setSpawnList();
game.startGame();
game.difficulty = 6;
level.isBuildRun = true;
for (let i = 0; i < build.list.length; i++) {
if (build.list[i].type === "field") {
mech.fieldUpgrades[build.list[i].index].effect();
} else if (build.list[i].type === "gun") {
b.giveGuns(build.list[i].index)
} else if (build.list[i].type === "mod") {
b.giveMod(build.list[i].index)
}
}
}
}
document.getElementById("build-button").addEventListener("click", () => {
document.getElementById("build-button").style.display = "none";
const el = document.getElementById("build-grid")
if (build.isShowingBuilds) {
el.style.display = "none"
build.isShowingBuilds = false
document.body.style.overflow = "hidden"
document.getElementById("controls").style.display = 'inline'
document.getElementById("settings").style.display = 'inline'
} else {
build.list = []
// let text = '<p>choose up to 5 powers<br> <button type="button" id="build-begin-button" onclick="build.startBuildRun()">Begin Run</button></p>'
let text =
`<div style="display: flex; justify-content: center; align-items: center;">
<svg class="SVG-button" onclick="build.startBuildRun()" width="90" height="40">
<g stroke='none' fill='#333' stroke-width="2" font-size="30px" font-family="Ariel, sans-serif">
<text x="15" y="31">start</text>
</g>
</svg>
</div>
<div class="build-grid-module" style="font-size: 19px; line-height: 110%;">
Choose up to five power ups. Once you start, only health and ammo will drop, so pick carefully.
</div>`
for (let i = 1, len = mech.fieldUpgrades.length; i < len; i++) {
text += `<div class="build-grid-module" onclick="build.choosePowerUp(this,${i},'field')" ><div class="circle-grid field"></div> &nbsp; <strong style='font-size:1.3em;'>${mech.fieldUpgrades[i].name}</strong><br> ${mech.fieldUpgrades[i].description}</div>`
}
for (let i = 0, len = b.guns.length; i < len; i++) {
text += `<div class="build-grid-module" onclick="build.choosePowerUp(this,${i},'gun')"><div class="circle-grid gun"></div> &nbsp; <strong style='font-size:1.3em;'>${b.guns[i].name}</strong><br> ${b.guns[i].description}</div>`
}
for (let i = 0, len = b.mods.length; i < len; i++) {
text += `<div class="build-grid-module" onclick="build.choosePowerUp(this,${i},'mod')"><div class="circle-grid mod"></div> &nbsp; <strong style='font-size:1.3em;'>${b.mods[i].name}</strong><br> ${b.mods[i].description}</div>`
}
el.innerHTML = text
el.style.display = "grid"
build.isShowingBuilds = true
document.body.style.overflowY = "scroll";
document.body.style.overflowX = "hidden";
document.getElementById("controls").style.display = 'none'
document.getElementById("settings").style.display = 'none'
}
});
//set up canvas
var canvas = document.getElementById("canvas");
//using "const" causes problems in safari when an ID shares the same name.
const ctx = canvas.getContext("2d");
document.body.style.backgroundColor = "#fff";
//disable pop up menu on right click
document.oncontextmenu = function () {
return false;
}
function setupCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.width2 = canvas.width / 2; //precalculated because I use this often (in mouse look)
canvas.height2 = canvas.height / 2;
canvas.diagonal = Math.sqrt(canvas.width2 * canvas.width2 + canvas.height2 * canvas.height2);
ctx.font = "15px Arial";
ctx.lineJoin = "round";
ctx.lineCap = "round";
// ctx.lineCap='square';
game.setZoom();
}
setupCanvas();
window.onresize = () => {
setupCanvas();
};
//mouse move input
document.body.addEventListener("mousemove", (e) => {
game.mouse.x = e.clientX;
game.mouse.y = e.clientY;
});
document.body.addEventListener("mouseup", (e) => {
// game.buildingUp(e); //uncomment when building levels
// game.mouseDown = false;
// console.log(e)
if (e.which === 3) {
game.mouseDownRight = false;
} else {
game.mouseDown = false;
}
});
document.body.addEventListener("mousedown", (e) => {
if (e.which === 3) {
game.mouseDownRight = true;
} else {
game.mouseDown = true;
}
});
//keyboard input
const keys = [];
document.body.addEventListener("keydown", (e) => {
keys[e.keyCode] = true;
game.keyPress();
});
document.body.addEventListener("keyup", (e) => {
keys[e.keyCode] = false;
});
document.body.addEventListener("wheel", (e) => {
if (e.deltaY > 0) {
game.nextGun();
} else {
game.previousGun();
}
}, {
passive: true
});
document.getElementById("fps-select").addEventListener("input", () => {
let value = document.getElementById("fps-select").value
if (value === 'max') {
game.fpsCapDefault = 999999999;
} else if (value === '72') {
game.fpsCapDefault = 72
} else if (value === '60') {
game.fpsCapDefault = 60
} else if (value === '45') {
game.fpsCapDefault = 45
} else if (value === '30') {
game.fpsCapDefault = 30
} else if (value === '15') {
game.fpsCapDefault = 15
}
});
document.getElementById("body-damage").addEventListener("input", () => {
game.isBodyDamage = document.getElementById("body-damage").checked
});
// function playSound(id) {
// //play sound
// if (false) {
// //sounds are turned off for now
// // if (document.getElementById(id)) {
// var sound = document.getElementById(id); //setup audio
// sound.currentTime = 0; //reset position of playback to zero //sound.load();
// sound.play();
// }
// }
function shuffle(array) {
var currentIndex = array.length,
temporaryValue,
randomIndex;
// While there remain elements to shuffle...
while (0 !== currentIndex) {
// Pick a remaining element...
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
// And swap it with the current element.
temporaryValue = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temporaryValue;
}
return array;
}
//main loop ************************************************************
//**********************************************************************
function cycle() {
if (!game.paused) requestAnimationFrame(cycle);
const now = Date.now();
const elapsed = now - game.then; // calc elapsed time since last loop
if (elapsed > game.fpsInterval) { // if enough time has elapsed, draw the next frame
game.then = now - (elapsed % game.fpsInterval); // Get ready for next frame by setting then=now. Also, adjust for fpsInterval not being multiple of 16.67
game.loop();
}
"use strict";
/* TODO: *******************************************
*****************************************************
add builds with combinations of gun, field and mobs
use the pull down menu
dynamically generate html about fields, guns and mods
add grid check to improve queries over large body arrays
something about broad phase
having trouble with this, might give up
gun: like drones, but fast moving and short lived
dies after doing damage
gun: Spirit Bomb (singularity)
use charge up like rail gun
electricity graphics like plasma torch
suck in nearby mobs, power ups?, blocks?
sucked in stuff increase size
uses energy
mod: auto pick up guns, heals, ammo
use the same rule for drones
maybe give some other bonus too?
rework junk bot
it's behavior is too unpredictable
range is unclear
having the bullets last long after doing dmg isn't fun
we want a fun gun that acts like a melee weapon
atmosphere levels
large rotating fan that the player has to move through
give the user a rest, between combat
low combat
nonaggressive mobs
one mob attacking the passive mobs
more graphics
Boss levels
boss grows and spilt, if you don't kill it fast
sensor that locks you in after you enter the boss room
boss that eats other mobs and gains stats from them
chance to spawn on any level (past level 5)
boss that knows how to shoot (player) bullets that collide with player
overwrite custom engine collision bullet mob function.
add a key that player picks up and needs to set on the exit door to open it
make power ups keep moving to player if the pickup field is turned off before they get picked up
not sure how to do this without adding a constant check
animate new level spawn by having the map aspects randomly fly into place
new map with repeating endlessness
get ideas from Manifold Garden game
if falling, get teleported above the map
I tried it, but had trouble getting the camera to adjust to the teleportation
this can apply to blocks mobs, and power ups as well
field power up effects
field allows player to hold and throw living mobs
mod power ups ideas
double jump
bullet on mob damage effects
add to the array mob.do new mob behaviors
add a damage over time
add a freeze
give mobs more animal-like behaviors
like rain world
give mobs something to do when they don't see player
explore map
eat power ups
drop power up (if killed after eating one)
mobs some times aren't aggressive
when low on life or after taking a large hit
mobs can fight each other
this might be hard to code
isolated mobs try to group up.
game mechanics
mechanics that support the physics engine
add rope/constraint
get ideas from game: limbo / inside
environmental hazards
laser
lava
button / switch
door
fizzler
moving platform
map zones
water
low friction ground
bouncy ground
// collision info:
category mask
powerUp: 0x100000 0x100001
body: 0x010000 0x011111
player: 0x001000 0x010011
bullet: 0x000100 0x010011
mob: 0x000010 0x011111
mobBullet: 0x000010 0x011101
mobShield: 0x000010 0x001100
map: 0x000001 0x111111
*/
//build build grid display
const build = {
isShowingBuilds: false,
list: [],
choosePowerUp(who, index, type) {
//check if matching a current power up
for (let i = 0; i < build.list.length; i++) {
if (build.list[i].index === index && build.list[i].type === type) { //if already click, toggle off
build.list.splice(i, 1);
who.style.backgroundColor = "#fff"
return
}
}
//check if trying to get a second field
if (type === "field") {
for (let i = 0; i < build.list.length; i++) {
if (build.list[i].type === "field") { //if already click, toggle off
build.list[i].who.style.backgroundColor = "#fff"
build.list.splice(i, 1);
}
}
}
if (build.list.length < 5) { //add to build array
// who.style.border = "2px solid #333"
who.style.backgroundColor = "#919ba8" //"#868f9a"
build.list[build.list.length] = {
who: who,
index: index,
type: type
}
}
},
startBuildRun() {
spawn.setSpawnList();
spawn.setSpawnList();
game.startGame();
game.difficulty = 6;
level.isBuildRun = true;
for (let i = 0; i < build.list.length; i++) {
if (build.list[i].type === "field") {
mech.fieldUpgrades[build.list[i].index].effect();
} else if (build.list[i].type === "gun") {
b.giveGuns(build.list[i].index)
} else if (build.list[i].type === "mod") {
b.giveMod(build.list[i].index)
}
}
}
}
document.getElementById("build-button").addEventListener("click", () => {
document.getElementById("build-button").style.display = "none";
const el = document.getElementById("build-grid")
if (build.isShowingBuilds) {
el.style.display = "none"
build.isShowingBuilds = false
document.body.style.overflow = "hidden"
document.getElementById("controls").style.display = 'inline'
document.getElementById("settings").style.display = 'inline'
} else {
build.list = []
// let text = '<p>choose up to 5 powers<br> <button type="button" id="build-begin-button" onclick="build.startBuildRun()">Begin Run</button></p>'
let text =
`<div style="display: flex; justify-content: center; align-items: center;">
<svg class="SVG-button" onclick="build.startBuildRun()" width="90" height="40">
<g stroke='none' fill='#333' stroke-width="2" font-size="30px" font-family="Ariel, sans-serif">
<text x="15" y="31">start</text>
</g>
</svg>
</div>
<div class="build-grid-module" style="font-size: 19px; line-height: 110%;">
Choose up to five power ups. Once you start, only health and ammo will drop, so pick carefully.
</div>`
for (let i = 1, len = mech.fieldUpgrades.length; i < len; i++) {
text += `<div class="build-grid-module" onclick="build.choosePowerUp(this,${i},'field')" ><div class="circle-grid field"></div> &nbsp; <strong style='font-size:1.3em;'>${mech.fieldUpgrades[i].name}</strong><br> ${mech.fieldUpgrades[i].description}</div>`
}
for (let i = 0, len = b.guns.length; i < len; i++) {
text += `<div class="build-grid-module" onclick="build.choosePowerUp(this,${i},'gun')"><div class="circle-grid gun"></div> &nbsp; <strong style='font-size:1.3em;'>${b.guns[i].name}</strong><br> ${b.guns[i].description}</div>`
}
for (let i = 0, len = b.mods.length; i < len; i++) {
text += `<div class="build-grid-module" onclick="build.choosePowerUp(this,${i},'mod')"><div class="circle-grid mod"></div> &nbsp; <strong style='font-size:1.3em;'>${b.mods[i].name}</strong><br> ${b.mods[i].description}</div>`
}
el.innerHTML = text
el.style.display = "grid"
build.isShowingBuilds = true
document.body.style.overflowY = "scroll";
document.body.style.overflowX = "hidden";
document.getElementById("controls").style.display = 'none'
document.getElementById("settings").style.display = 'none'
}
});
//set up canvas
var canvas = document.getElementById("canvas");
//using "const" causes problems in safari when an ID shares the same name.
const ctx = canvas.getContext("2d");
document.body.style.backgroundColor = "#fff";
//disable pop up menu on right click
document.oncontextmenu = function () {
return false;
}
function setupCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.width2 = canvas.width / 2; //precalculated because I use this often (in mouse look)
canvas.height2 = canvas.height / 2;
canvas.diagonal = Math.sqrt(canvas.width2 * canvas.width2 + canvas.height2 * canvas.height2);
ctx.font = "15px Arial";
ctx.lineJoin = "round";
ctx.lineCap = "round";
// ctx.lineCap='square';
game.setZoom();
}
setupCanvas();
window.onresize = () => {
setupCanvas();
};
//mouse move input
document.body.addEventListener("mousemove", (e) => {
game.mouse.x = e.clientX;
game.mouse.y = e.clientY;
});
document.body.addEventListener("mouseup", (e) => {
// game.buildingUp(e); //uncomment when building levels
// game.mouseDown = false;
// console.log(e)
if (e.which === 3) {
game.mouseDownRight = false;
} else {
game.mouseDown = false;
}
});
document.body.addEventListener("mousedown", (e) => {
if (e.which === 3) {
game.mouseDownRight = true;
} else {
game.mouseDown = true;
}
});
//keyboard input
const keys = [];
document.body.addEventListener("keydown", (e) => {
keys[e.keyCode] = true;
game.keyPress();
});
document.body.addEventListener("keyup", (e) => {
keys[e.keyCode] = false;
});
document.body.addEventListener("wheel", (e) => {
if (e.deltaY > 0) {
game.nextGun();
} else {
game.previousGun();
}
}, {
passive: true
});
document.getElementById("fps-select").addEventListener("input", () => {
let value = document.getElementById("fps-select").value
if (value === 'max') {
game.fpsCapDefault = 999999999;
} else if (value === '72') {
game.fpsCapDefault = 72
} else if (value === '60') {
game.fpsCapDefault = 60
} else if (value === '45') {
game.fpsCapDefault = 45
} else if (value === '30') {
game.fpsCapDefault = 30
} else if (value === '15') {
game.fpsCapDefault = 15
}
});
document.getElementById("body-damage").addEventListener("input", () => {
game.isBodyDamage = document.getElementById("body-damage").checked
});
// function playSound(id) {
// //play sound
// if (false) {
// //sounds are turned off for now
// // if (document.getElementById(id)) {
// var sound = document.getElementById(id); //setup audio
// sound.currentTime = 0; //reset position of playback to zero //sound.load();
// sound.play();
// }
// }
function shuffle(array) {
var currentIndex = array.length,
temporaryValue,
randomIndex;
// While there remain elements to shuffle...
while (0 !== currentIndex) {
// Pick a remaining element...
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
// And swap it with the current element.
temporaryValue = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temporaryValue;
}
return array;
}
//main loop ************************************************************
//**********************************************************************
function cycle() {
if (!game.paused) requestAnimationFrame(cycle);
const now = Date.now();
const elapsed = now - game.then; // calc elapsed time since last loop
if (elapsed > game.fpsInterval) { // if enough time has elapsed, draw the next frame
game.then = now - (elapsed % game.fpsInterval); // Get ready for next frame by setting then=now. Also, adjust for fpsInterval not being multiple of 16.67
game.loop();
}
}

File diff suppressed because it is too large Load Diff

2020
js/mobs.js

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,239 +1,239 @@
let powerUp = [];
const powerUps = {
heal: {
name: "heal",
color: "#0fb",
size() {
return 40 * Math.sqrt(0.1 + Math.random() * 0.5);
},
effect() {
let heal = (this.size / 40) ** 2
if (b.fullHeal) heal = Infinity
heal = Math.min(1 - mech.health, heal)
mech.addHealth(heal);
if (heal > 0) game.makeTextLog("<div class='circle heal'></div> &nbsp; <span style='font-size:115%;'> <strong style = 'letter-spacing: 2px;'>heal</strong> " + (heal * 100).toFixed(0) + "%</span>", 300)
}
},
ammo: {
name: "ammo",
color: "#467",
size() {
return 17;
},
effect() {
//only get ammo for guns player has
let target;
// console.log(b.inventory.length)
if (b.inventory.length > 0) {
//add ammo to a gun in inventory
target = b.guns[b.inventory[Math.floor(Math.random() * (b.inventory.length))]];
//try 3 more times to give ammo to a gun with ammo, not Infinity
if (target.ammo === Infinity) {
target = b.guns[b.inventory[Math.floor(Math.random() * (b.inventory.length))]]
if (target.ammo === Infinity) {
target = b.guns[b.inventory[Math.floor(Math.random() * (b.inventory.length))]]
if (target.ammo === Infinity) target = b.guns[b.inventory[Math.floor(Math.random() * (b.inventory.length))]]
}
}
} else {
//if you don't have any guns just add ammo to a random gun you don't have yet
target = b.guns[Math.floor(Math.random() * b.guns.length)];
}
if (target.ammo === Infinity) {
mech.fieldMeter = 1;
if (!game.lastLogTime) game.makeTextLog("<span style='font-size:115%;'><span class='color-f'>+energy</span></span>", 300);
} else {
//ammo given scales as mobs take more hits to kill
let ammo = Math.ceil((target.ammoPack * (0.45 + 0.06 * Math.random())) / Math.sqrt(b.dmgScale));
if (level.isBuildRun) ammo = Math.floor(ammo * 1.2)
target.ammo += ammo;
game.updateGunHUD();
game.makeTextLog("<div class='circle gun'></div> &nbsp; <span style='font-size:110%;'>+" + ammo + " ammo for " + target.name + "</span>", 300);
}
}
},
field: {
name: "field",
color: "#0cf",
size() {
return 45;
},
effect() {
const previousMode = mech.fieldMode
if (!this.mode) { //this.mode is set if the power up has been ejected from player
mode = mech.fieldMode
while (mode === mech.fieldMode) {
mode = Math.ceil(Math.random() * (mech.fieldUpgrades.length - 1))
}
mech.fieldUpgrades[mode].effect(); //choose random field upgrade that you don't already have
} else {
mech.fieldUpgrades[this.mode].effect(); //set a predetermined power up
}
//pop the old field out in case player wants to swap back
if (previousMode !== 0) {
mech.fieldCDcycle = mech.cycle + 40; //trigger fieldCD to stop power up grab automatic pick up of spawn
powerUps.spawn(mech.pos.x, mech.pos.y - 15, "field", false, previousMode);
}
}
},
mod: {
name: "mod",
color: "#a8f",
size() {
return 42;
},
effect() {
//find what mods I don't have
let options = [];
for (let i = 0; i < b.mods.length; i++) {
if (!b.mods[i].have) options.push(i);
}
//give a random mod from the mods I don't have
if (options.length > 0) {
let newMod = options[Math.floor(Math.random() * options.length)]
b.giveMod(newMod)
game.replaceTextLog = true;
game.makeTextLog(`<div class="circle mod"></div> &nbsp; <strong style='font-size:30px;'>${b.mods[newMod].name}</strong><br><br> ${b.mods[newMod].description}`, 1000);
game.replaceTextLog = false;
}
}
},
gun: {
name: "gun",
color: "#26a",
size() {
return 35;
},
effect() {
//find what guns I don't have
let options = [];
if (b.activeGun === null && game.difficulty < 3) {
//choose the first gun to be one that is good for the early game
for (let i = 0; i < b.guns.length; ++i) {
if (!b.guns[i].have && b.guns[i].isStarterGun) options.push(i);
}
} else {
//choose a gun you don't have
for (let i = 0; i < b.guns.length; ++i) {
if (!b.guns[i].have) options.push(i);
}
}
//give player a gun they don't already have if possible
game.replaceTextLog = true;
if (options.length > 0) {
let newGun = options[Math.floor(Math.random() * options.length)];
if (b.activeGun === null) b.activeGun = newGun //if no active gun switch to new gun
game.makeTextLog(`${game.SVGleftMouse} <strong style='font-size:30px;'>${b.guns[newGun].name}</strong><br><br>${b.guns[newGun].description}`, 900);
b.guns[newGun].have = true;
b.inventory.push(newGun);
b.guns[newGun].ammo += b.guns[newGun].ammoPack * 2;
game.makeGunHUD();
} else {
//if you have all guns then get ammo
const ammoTarget = Math.floor(Math.random() * (b.guns.length));
const ammo = Math.ceil(b.guns[ammoTarget].ammoPack * 2);
b.guns[ammoTarget].ammo += ammo;
game.updateGunHUD();
game.makeTextLog("<span style='font-size:110%;'>+" + ammo + " ammo for " + b.guns[ammoTarget].name + "</span>", 300);
}
game.replaceTextLog = false
}
},
spawnRandomPowerUp(x, y) { //mostly used after mob dies
if (Math.random() * Math.random() - 0.25 > Math.sqrt(mech.health) || Math.random() < 0.04) { //spawn heal chance is higher at low health
powerUps.spawn(x, y, "heal");
if (Math.random() < b.modMoreDrops) powerUps.spawn(x, y, "heal");
return;
}
if (Math.random() < 0.2 && b.inventory.length > 0) {
powerUps.spawn(x, y, "ammo");
if (Math.random() < b.modMoreDrops) powerUps.spawn(x, y, "ammo");
return;
}
if (Math.random() < 0.004 * (4 - b.inventory.length)) { //a new gun has a low chance for each not acquired gun to drop
powerUps.spawn(x, y, "gun");
if (Math.random() < b.modMoreDrops) powerUps.spawn(x, y, "gun");
return;
}
if (Math.random() < 0.004 * (7 - b.modCount)) {
powerUps.spawn(x, y, "mod");
if (Math.random() < b.modMoreDrops) powerUps.spawn(x, y, "mod");
return;
}
if (Math.random() < 0.005) {
powerUps.spawn(x, y, "field");
if (Math.random() < b.modMoreDrops) powerUps.spawn(x, y, "field");
return;
}
},
spawnBossPowerUp(x, y) { //boss spawns field and gun mod upgrades
if (mech.fieldMode === 0) {
powerUps.spawn(x, y, "field")
if (Math.random() < b.modMoreDrops) powerUps.spawn(x, y, "field")
} else if (Math.random() < 0.3) {
powerUps.spawn(x, y, "mod")
if (Math.random() < b.modMoreDrops) powerUps.spawn(x, y, "mod")
} else if (Math.random() < 0.3) {
powerUps.spawn(x, y, "field");
if (Math.random() < b.modMoreDrops) powerUps.spawn(x, y, "field");
} else if (Math.random() < 0.3) {
powerUps.spawn(x, y, "gun")
if (Math.random() < b.modMoreDrops) powerUps.spawn(x, y, "gun")
} else if (mech.health < 0.6) {
powerUps.spawn(x, y, "heal");
if (Math.random() < b.modMoreDrops) powerUps.spawn(x, y, "heal");
} else {
powerUps.spawn(x, y, "ammo");
if (Math.random() < b.modMoreDrops) powerUps.spawn(x, y, "ammo");
}
},
chooseRandomPowerUp(x, y) { //100% chance to drop a random power up //used in spawn.debris
if (Math.random() < 0.5) {
powerUps.spawn(x, y, "heal", false);
} else {
powerUps.spawn(x, y, "ammo", false);
}
},
spawnStartingPowerUps(x, y) { //used for map specific power ups, mostly to give player a starting gun
if (b.inventory.length < 2 || game.isEasyMode) {
powerUps.spawn(x, y, "gun", false); //starting gun
} else {
powerUps.spawnRandomPowerUp(x, y);
powerUps.spawnRandomPowerUp(x, y);
powerUps.spawnRandomPowerUp(x, y);
powerUps.spawnRandomPowerUp(x, y);
}
},
spawn(x, y, target, moving = true, mode = null) {
if (!level.isBuildRun || target === "heal" || target === "ammo") {
let i = powerUp.length;
target = powerUps[target];
size = target.size();
powerUp[i] = Matter.Bodies.polygon(x, y, 0, size, {
density: 0.001,
frictionAir: 0.01,
restitution: 0.8,
inertia: Infinity, //prevents rotation
collisionFilter: {
group: 0,
category: 0x100000,
mask: 0x100001
},
color: target.color,
effect: target.effect,
mode: mode,
name: target.name,
size: size
});
if (moving) {
Matter.Body.setVelocity(powerUp[i], {
x: (Math.random() - 0.5) * 15,
y: Math.random() * -9 - 3
});
}
World.add(engine.world, powerUp[i]); //add to world
}
},
let powerUp = [];
const powerUps = {
heal: {
name: "heal",
color: "#0fb",
size() {
return 40 * Math.sqrt(0.1 + Math.random() * 0.5);
},
effect() {
let heal = (this.size / 40) ** 2
if (b.fullHeal) heal = Infinity
heal = Math.min(1 - mech.health, heal)
mech.addHealth(heal);
if (heal > 0) game.makeTextLog("<div class='circle heal'></div> &nbsp; <span style='font-size:115%;'> <strong style = 'letter-spacing: 2px;'>heal</strong> " + (heal * 100).toFixed(0) + "%</span>", 300)
}
},
ammo: {
name: "ammo",
color: "#467",
size() {
return 17;
},
effect() {
//only get ammo for guns player has
let target;
// console.log(b.inventory.length)
if (b.inventory.length > 0) {
//add ammo to a gun in inventory
target = b.guns[b.inventory[Math.floor(Math.random() * (b.inventory.length))]];
//try 3 more times to give ammo to a gun with ammo, not Infinity
if (target.ammo === Infinity) {
target = b.guns[b.inventory[Math.floor(Math.random() * (b.inventory.length))]]
if (target.ammo === Infinity) {
target = b.guns[b.inventory[Math.floor(Math.random() * (b.inventory.length))]]
if (target.ammo === Infinity) target = b.guns[b.inventory[Math.floor(Math.random() * (b.inventory.length))]]
}
}
} else {
//if you don't have any guns just add ammo to a random gun you don't have yet
target = b.guns[Math.floor(Math.random() * b.guns.length)];
}
if (target.ammo === Infinity) {
mech.fieldMeter = 1;
if (!game.lastLogTime) game.makeTextLog("<span style='font-size:115%;'><span class='color-f'>+energy</span></span>", 300);
} else {
//ammo given scales as mobs take more hits to kill
let ammo = Math.ceil((target.ammoPack * (0.45 + 0.06 * Math.random())) / Math.sqrt(b.dmgScale));
if (level.isBuildRun) ammo = Math.floor(ammo * 1.2)
target.ammo += ammo;
game.updateGunHUD();
game.makeTextLog("<div class='circle gun'></div> &nbsp; <span style='font-size:110%;'>+" + ammo + " ammo for " + target.name + "</span>", 300);
}
}
},
field: {
name: "field",
color: "#0cf",
size() {
return 45;
},
effect() {
const previousMode = mech.fieldMode
if (!this.mode) { //this.mode is set if the power up has been ejected from player
mode = mech.fieldMode
while (mode === mech.fieldMode) {
mode = Math.ceil(Math.random() * (mech.fieldUpgrades.length - 1))
}
mech.fieldUpgrades[mode].effect(); //choose random field upgrade that you don't already have
} else {
mech.fieldUpgrades[this.mode].effect(); //set a predetermined power up
}
//pop the old field out in case player wants to swap back
if (previousMode !== 0) {
mech.fieldCDcycle = mech.cycle + 40; //trigger fieldCD to stop power up grab automatic pick up of spawn
powerUps.spawn(mech.pos.x, mech.pos.y - 15, "field", false, previousMode);
}
}
},
mod: {
name: "mod",
color: "#a8f",
size() {
return 42;
},
effect() {
//find what mods I don't have
let options = [];
for (let i = 0; i < b.mods.length; i++) {
if (!b.mods[i].have) options.push(i);
}
//give a random mod from the mods I don't have
if (options.length > 0) {
let newMod = options[Math.floor(Math.random() * options.length)]
b.giveMod(newMod)
game.replaceTextLog = true;
game.makeTextLog(`<div class="circle mod"></div> &nbsp; <strong style='font-size:30px;'>${b.mods[newMod].name}</strong><br><br> ${b.mods[newMod].description}`, 1000);
game.replaceTextLog = false;
}
}
},
gun: {
name: "gun",
color: "#26a",
size() {
return 35;
},
effect() {
//find what guns I don't have
let options = [];
if (b.activeGun === null && game.difficulty < 3) {
//choose the first gun to be one that is good for the early game
for (let i = 0; i < b.guns.length; ++i) {
if (!b.guns[i].have && b.guns[i].isStarterGun) options.push(i);
}
} else {
//choose a gun you don't have
for (let i = 0; i < b.guns.length; ++i) {
if (!b.guns[i].have) options.push(i);
}
}
//give player a gun they don't already have if possible
game.replaceTextLog = true;
if (options.length > 0) {
let newGun = options[Math.floor(Math.random() * options.length)];
if (b.activeGun === null) b.activeGun = newGun //if no active gun switch to new gun
game.makeTextLog(`${game.SVGleftMouse} <strong style='font-size:30px;'>${b.guns[newGun].name}</strong><br><br>${b.guns[newGun].description}`, 900);
b.guns[newGun].have = true;
b.inventory.push(newGun);
b.guns[newGun].ammo += b.guns[newGun].ammoPack * 2;
game.makeGunHUD();
} else {
//if you have all guns then get ammo
const ammoTarget = Math.floor(Math.random() * (b.guns.length));
const ammo = Math.ceil(b.guns[ammoTarget].ammoPack * 2);
b.guns[ammoTarget].ammo += ammo;
game.updateGunHUD();
game.makeTextLog("<span style='font-size:110%;'>+" + ammo + " ammo for " + b.guns[ammoTarget].name + "</span>", 300);
}
game.replaceTextLog = false
}
},
spawnRandomPowerUp(x, y) { //mostly used after mob dies
if (Math.random() * Math.random() - 0.25 > Math.sqrt(mech.health) || Math.random() < 0.04) { //spawn heal chance is higher at low health
powerUps.spawn(x, y, "heal");
if (Math.random() < b.modMoreDrops) powerUps.spawn(x, y, "heal");
return;
}
if (Math.random() < 0.2 && b.inventory.length > 0) {
powerUps.spawn(x, y, "ammo");
if (Math.random() < b.modMoreDrops) powerUps.spawn(x, y, "ammo");
return;
}
if (Math.random() < 0.004 * (4 - b.inventory.length)) { //a new gun has a low chance for each not acquired gun to drop
powerUps.spawn(x, y, "gun");
if (Math.random() < b.modMoreDrops) powerUps.spawn(x, y, "gun");
return;
}
if (Math.random() < 0.0035 * (7 - b.modCount)) {
powerUps.spawn(x, y, "mod");
if (Math.random() < b.modMoreDrops) powerUps.spawn(x, y, "mod");
return;
}
if (Math.random() < 0.005) {
powerUps.spawn(x, y, "field");
if (Math.random() < b.modMoreDrops) powerUps.spawn(x, y, "field");
return;
}
},
spawnBossPowerUp(x, y) { //boss spawns field and gun mod upgrades
if (mech.fieldMode === 0) {
powerUps.spawn(x, y, "field")
if (Math.random() < b.modMoreDrops) powerUps.spawn(x, y, "field")
} else if (Math.random() < 0.27) {
powerUps.spawn(x, y, "mod")
if (Math.random() < b.modMoreDrops) powerUps.spawn(x, y, "mod")
} else if (Math.random() < 0.27) {
powerUps.spawn(x, y, "field");
if (Math.random() < b.modMoreDrops) powerUps.spawn(x, y, "field");
} else if (Math.random() < 0.27) {
powerUps.spawn(x, y, "gun")
if (Math.random() < b.modMoreDrops) powerUps.spawn(x, y, "gun")
} else if (mech.health < 0.6) {
powerUps.spawn(x, y, "heal");
if (Math.random() < b.modMoreDrops) powerUps.spawn(x, y, "heal");
} else {
powerUps.spawn(x, y, "ammo");
if (Math.random() < b.modMoreDrops) powerUps.spawn(x, y, "ammo");
}
},
chooseRandomPowerUp(x, y) { //100% chance to drop a random power up //used in spawn.debris
if (Math.random() < 0.5) {
powerUps.spawn(x, y, "heal", false);
} else {
powerUps.spawn(x, y, "ammo", false);
}
},
spawnStartingPowerUps(x, y) { //used for map specific power ups, mostly to give player a starting gun
if (b.inventory.length < 2 || game.isEasyMode) {
powerUps.spawn(x, y, "gun", false); //starting gun
} else {
powerUps.spawnRandomPowerUp(x, y);
powerUps.spawnRandomPowerUp(x, y);
powerUps.spawnRandomPowerUp(x, y);
powerUps.spawnRandomPowerUp(x, y);
}
},
spawn(x, y, target, moving = true, mode = null) {
if (!level.isBuildRun || target === "heal" || target === "ammo") {
let i = powerUp.length;
target = powerUps[target];
size = target.size();
powerUp[i] = Matter.Bodies.polygon(x, y, 0, size, {
density: 0.001,
frictionAir: 0.01,
restitution: 0.8,
inertia: Infinity, //prevents rotation
collisionFilter: {
group: 0,
category: 0x100000,
mask: 0x100001
},
color: target.color,
effect: target.effect,
mode: mode,
name: target.name,
size: size
});
if (moving) {
Matter.Body.setVelocity(powerUp[i], {
x: (Math.random() - 0.5) * 15,
y: Math.random() * -9 - 3
});
}
World.add(engine.world, powerUp[i]); //add to world
}
},
};

File diff suppressed because it is too large Load Diff