added 5 new mods, power up display, game balance

This commit is contained in:
landgreen
2019-12-01 18:22:50 -08:00
parent 927933a754
commit 65977ce5aa
10 changed files with 524 additions and 397 deletions

View File

@@ -30,7 +30,6 @@
</head>
<body>
<!-- <body oncontextmenu="return false"> -->
<div id='guns'></div>
<div id='field'></div>
@@ -77,34 +76,82 @@
<canvas id="canvas"></canvas>
<!-- ********** intro page ***********************************************
******************************************************************************* -->
<!-- <div id="build-details">
<div class="build-grid-module"></div>
<details>
<summary>build</summary>
<div id="details-div">
</div>
</details>
</div> -->
<div id="build-grid">
</div>
<button type="button" id="build-button">builds</button>
<!-- <div id="build">
<details>
<summary>builds</summary>
</details>
</div> -->
<div id="controls">
<details>
<summary>info</summary>
<summary>about</summary>
<div id="details-div">
<div style="line-height: 150%;">
<label for="difficulty-select" title="effects: number of mobs, damage done by mobs, damage done to mobs, mob speed">combat difficulty:</label>
<select name="difficulty-select" id="difficulty-select">
<option value="easy">easy</option>
<option value="0" selected>normal</option>
<option value="4">hard</option>
<option value="8">why...</option>
</select>
<br>
<label for="body-damage" title="allow damage from heavy, fast moving blocks">collision damage from blocks:</label>
<input type="checkbox" id="body-damage" name="body-damage" checked style="width:16px; height:16px;">
<br>
<label for="fps-select" title="use this to slow the game down">frames per second cap:</label>
<select name="fps-select" id="fps-select">
<option value="max">no fps cap</option>
<option value="72" selected>72 fps cap</option>
<option value="60">60 fps cap</option>
<option value="45">45 fps cap</option>
<option value="30">30 fps cap</option>
</select>
</div>
<br><br>
<table>
<tr>
<td>FIRE</td>
<th>FIRE</th>
<td>left mouse</td>
<td></td>
</tr>
<tr>
<td>FIELD</td>
<th>FIELD</th>
<td>right mouse / spacebar</td>
</tr>
<tr>
<td>MOVE</td>
<th>MOVE</th>
<td>WASD / arrows</td>
</tr>
<tr>
<td>GUNS</td>
<th>GUNS</th>
<td>Q / E / mouse wheel</td>
</tr>
<tr>
<td>ZOOM</td>
<th>ZOOM</th>
<td>+ / -</td>
</tr>
<tr>
<td>PAUSE</td>
<th>PAUSE</th>
<td>P</td>
</tr>
<!-- <tr>
@@ -140,35 +187,9 @@
<a href="https://github.com/landgreen/n-gon">Github</a> hosts the source code for n-gon.<br> It's written in JavaScript, CSS, and HTML.
<br>
<br>
N-gon is also on <a href="https://lilgreenland.itch.io/n-gon">itch.io</a>.
n-gon is also hosted at <a href="https://lilgreenland.itch.io/n-gon">itch.io</a>.
<br>
<br>
</div>
</details>
</div>
<div id="settings">
<details>
<summary>settings</summary>
<div id="details-div">
<label for="body-damage" title="allow damage from heavy, fast moving blocks">block collision damage:</label>
<input type="checkbox" id="body-damage" name="body-damage" checked>
<br><br>
<label for="difficulty-select" title="effects: number of mobs, damage done by mobs, damage done to mobs, mob speed">combat difficulty:</label>
<select name="difficulty-select" id="difficulty-select">
<option value="easy">easy</option>
<option value="0" selected>normal</option>
<option value="4">hard</option>
<option value="8">why...</option>
</select>
<br><br>
<label for="fps-select" title="use this to slow the game down">FPS cap:</label>
<select name="fps-select" id="fps-select">
<option value="max">no fps cap</option>
<option value="72" selected>72 fps cap</option>
<option value="60">60 fps cap</option>
<option value="45">45 fps cap</option>
<option value="30">30 fps cap</option>
</select>
</div>
</details>
</div>

View File

@@ -19,7 +19,12 @@ const b = {
modExtraDmg: null,
annihilation: null,
fullHeal: null,
modSquirrelFx: 1,
modSquirrelFx: null,
modIsCrit: null,
modMoreDrops: null,
isModLowHealthDmg: null,
isModFarAwayDmg: null,
isModMonogamy: null,
setModDefaults() {
b.modCount = 0;
b.modFireRate = 1;
@@ -37,6 +42,11 @@ const b = {
b.modAnnihilation = false;
b.isModFullHeal = false;
b.modSquirrelFx = 1;
b.modIsCrit = false;
b.modMoreDrops = 0;
b.isModLowHealthDmg = false;
b.isModFarAwayDmg = false;
b.isModMonogamy = false;
mech.Fx = 0.015;
mech.jumpForce = 0.38;
mech.throwChargeRate = 2;
@@ -47,17 +57,17 @@ const b = {
},
mods: [{
name: "depleted uranium rounds",
description: "your <strong class='color-b'>bullets</strong> are larger and do more physical <span class='color-d'>damage</span>",
description: "your <strong>bullets</strong> are 10% larger<br>increased momentum and physical <strong class='color-d'>damage</strong>",
have: false, //0
effect: () => {
//good for guns that do mostly projectile damage:
//testing at 1.08: spray(point blank)(+0.25), one shot(+0.16), wave beam(point blank)(+0.14)
b.modBulletSize = 1.07;
b.modBulletSize = 1.1;
}
},
{
name: "auto-loading heuristics",
description: "your rate of fire is 15% higher",
description: "your <strong>rate of fire</strong> is 15% higher",
have: false, //1
effect: () => { //good for guns with extra ammo: needles, M80, rapid fire, flak, super balls
b.modFireRate = 0.85
@@ -65,7 +75,7 @@ const b = {
},
{
name: "desublimated ammunition",
description: "use 50% less <strong class='color-b'>ammo</strong> when <strong>crouching</strong>",
description: "use 50% less <strong>ammo</strong> when <strong>crouching</strong>",
have: false, //2
effect: () => { //good with guns that have less ammo: one shot, grenades, missiles, super balls, spray
b.modNoAmmo = 1
@@ -73,7 +83,7 @@ const b = {
},
{
name: "Lorentzian topology",
description: "your <strong class='color-b'>bullets</strong> last 40% longer",
description: "your <strong>bullets</strong> last 40% <strong>longer</strong>",
have: false, //3
effect: () => { //good with: drones, super balls, spore, missiles, wave beam(range), rapid fire(range), flak(range)
b.isModBulletsLastLonger = 1.40
@@ -81,7 +91,7 @@ const b = {
},
{
name: "anti-matter cores",
description: "the radius of your <strong class='color-e'>explosions</strong> is doubled<br><span style='opacity:0.3;'>be careful</span>",
description: "the <strong>radius</strong> of your <strong class='color-e'>explosions</strong> is doubled<br><strong style='opacity:0.3;'>be careful</strong>",
have: false, //4
effect: () => { //at 1.4 gives a flat 40% increase, and increased range, balanced by limited guns and self damage
//testing at 1.3: grenade(+0.3), missiles, flak, M80
@@ -90,7 +100,7 @@ const b = {
},
{
name: "ceramic plating",
description: "you take no damage from area effects<br>immune to <strong class='color-e'>explosions</strong> and enemy fields",
description: "<strong>immune</strong> to <strong class='color-e'>explosions</strong> and enemy fields",
have: false, //5
effect: () => {
b.isModAoEImmunity = true; //good for guns with explosions
@@ -98,7 +108,7 @@ const b = {
},
{
name: "ablative synthesis",
description: "after taking <span class='color-d'>damage</span>, there is a chance that your damaged parts will be rebuilt as <strong class='color-b'>drones</strong>",
description: "rebuild your broken parts as <strong>drones</strong><br>chance to occur after taking <strong class='color-d'>damage</strong>",
have: false, //6
effect: () => { //makes dangerous situations more survivable
b.isModDroneOnDamage = true;
@@ -106,7 +116,7 @@ const b = {
},
{
name: "zoospore vector",
description: "when an enemy <span style='color: #888;'>dies</span> it has a 20% chance to release <strong class='color-s'>spores</strong>",
description: "enemies can discharge <strong class='color-s'>spores</strong> on <strong>death</strong><br><strong class='color-s'>spores</strong> seek out enemies",
have: false, //7
effect: () => { //good late game maybe?
b.modSpores = 0.20;
@@ -114,16 +124,15 @@ const b = {
},
{
name: "field siphon",
description: "regenerate <span class='color-f'>field energy</span> proportional to your <span class='color-d'>damage</span> done",
description: "gain <strong class='color-f'>energy</strong> proportional to <strong class='color-d'>damage</strong> done",
have: false, //8
effect: () => { //good with laser, and all fields
b.modEnergySiphon = 0.2;
b.modEnergySiphon = 0.15;
}
},
{
name: "entropy transfer",
description: "<span class='color-h'>heal</span> proportional to your <span class='color-d'>damage</span> done",
description: "<strong class='color-h'>heal</strong> proportional to <strong class='color-d'>damage</strong> done",
have: false, //9
effect: () => { //good with guns that overkill: one shot, grenade
b.modHealthDrain = 0.01;
@@ -131,7 +140,7 @@ const b = {
},
{
name: "quantum immortality",
description: "after you <strong style='color: #606;'>die</strong> continue in an <em>alternate reality</em><br>guns, ammo, and field are randomized",
description: "after <strong>dying</strong>, continue in an <em>alternate reality</em><br>guns, ammo, and field are randomized",
have: false, //10
effect: () => {
b.modIsImmortal = true;
@@ -139,7 +148,7 @@ const b = {
},
{
name: "fluoroantimonic acid",
description: "your bullets do extra chemical <span class='color-d'>damage</span> each time they make contact",
description: "each bullet does extra chemical <strong class='color-d'>damage</strong>",
have: false, //11
effect: () => { //good with guns that fire many bullets at low speeds, minigun, drones, junk-bots, shotgun, superballs, wavebeam
b.modExtraDmg = 0.1
@@ -147,7 +156,7 @@ const b = {
},
{
name: "annihilation",
description: "after you touch any enemy, they are <strong class='color-l'>annihilated</strong><br><em>touching enemies <span class='color-d'>damages</span> you, but <span class='color-d'>destroys</span> them</em>",
description: "after <strong>touching</strong> enemies, they are annihilated",
have: false, //12
effect: () => { //good with mods that heal: superconductive healing, entropy transfer
b.modAnnihilation = true
@@ -155,17 +164,16 @@ const b = {
},
{
name: "recursive healing",
description: "<span class='color-h'>heals</span> bring you to full health",
description: "<strong class='color-h'>healing</strong> power ups bring you to <strong>full health</strong>",
have: false, //13
effect: () => { // good with ablative synthesis, electrostatic field
b.isModFullHeal = true
effect: () => { // good with ablative synthesis, melee builds
}
},
{
name: "Gauss rifle",
description: "<span style='color:#f0f;'>magnetically</span> <strong>launch blocks</strong> at much higher speeds<br>carry more massive blocks<br><em>hold right click to charge up a throw and release to fire</em>",
description: "<strong>launch blocks</strong> at much higher speeds<br>carry more massive blocks",
have: false, //14
effect: () => { // good with ablative synthesis, electrostatic field
effect: () => { // good with guns that run out of ammo
b.isModFullHeal = true
mech.throwChargeRate = 4;
mech.throwChargeMax = 150;
@@ -174,15 +182,54 @@ const b = {
},
{
name: "squirrel-cage rotor",
description: "jump higher and move faster",
description: "your legs produce 20% more force<br><strong>jump</strong> higher and <strong>move</strong> faster",
have: false, //15
effect: () => { //
effect: () => { // good with melee builds, content skipping builds
b.modSquirrelFx = 1.2;
mech.Fx = 0.015 * b.modSquirrelFx;
mech.jumpForce = 0.38 * 1.1;
}
},
{
name: "fracture analysis",
description: "<strong>6x</strong> physical <strong class='color-d'>damage</strong> to unaware enemies<br><em>enemies aware of you have a health bar</em>",
have: false, //16
effect: () => { // good with high damage guns that strike from a distance: rail gun, drones, flechettes, spores, grenade, vacuum bomb
b.modIsCrit = true;
}
},
{
name: "kinetic bombardment",
description: "do extra <strong class='color-d'>damage</strong> from farther away<br><em>up to 50% increase at about 30 steps away</em>",
have: false, //17
effect: () => { // good with annihilation, melee builds
b.isModFarAwayDmg = true; //used in mob.damage()
}
},
{
name: "quasistatic equilibrium",
description: "do extra <strong class='color-d'>damage</strong> at low health<br><em>up to 50% increase when near death</em>",
have: false, //18
effect: () => { // good with annihilation, melee builds
b.isModLowHealthDmg = true; //used in mob.damage()
}
},
{
name: "Bayesian inference",
description: "<strong>20%</strong> chance for double <strong>power ups</strong> to drop",
have: false, //19
effect: () => { // good with long term planning
b.modMoreDrops = 0.20;
}
},
{
name: "monogamy",
description: "equipping your first gun reduces <strong class='color-d'>damage</strong> taken<br>scales by <strong>7%</strong> for each gun in your inventory",
have: false, //20
effect: () => { // good with long term planning
b.isModMonogamy = true
}
},
],
giveMod(i) {
b.mods[i].effect(); //give specific mod
@@ -226,7 +273,7 @@ const b = {
}
} else {
mech.fireCDcycle = mech.cycle + 30; //cooldown
// game.makeTextLog("<div style='font-size:140%;'>NO AMMO</div><span class = 'box'>E</span> / <span class = 'box'>Q</span>", 200);
// game.makeTextLog("<div style='font-size:140%;'>NO AMMO</div><strong class = 'box'>E</strong> / <strong class = 'box'>Q</strong>", 200);
game.replaceTextLog = true;
game.makeTextLog("<div style='font-size:140%;'>NO AMMO</div> <p style='font-size:90%;'><strong>Q</strong>, <strong>E</strong>, and <strong>mouse wheel</strong> change weapons</p>", 200);
}
@@ -496,7 +543,7 @@ const b = {
},
guns: [{
name: "laser", //0
description: "fire a <span style='color:#f00;'>beam</span> of coherent light<br>reflects off walls at 75% intensity<br>uses <span class='color-f'>energy</span> instead of ammunition",
description: "emit a beam of <strong class='color-d'>damaging</strong> coherent light<br>uses <strong class='color-f'>energy</strong> instead of ammunition",
ammo: 0,
// ammoPack: 350,
ammoPack: Infinity,
@@ -658,17 +705,18 @@ const b = {
},
{
name: "rail gun", //1
description: "<strong>hold left mouse</strong> to charge and release to fire<br>charging repels small enemies<br><em>crouching charges quicker and reduces recoil</em>",
description: "magnetically launch a dense rod<br><strong>hold left mouse</strong> to charge and <strong>repel</strong> enemies",
ammo: 0,
ammoPack: 12,
have: false,
isStarterGun: false,
fire() {
const me = bullet.length;
bullet[me] = Bodies.rectangle(9, -90, 0.01 * b.modBulletSize, 0.0017 * b.modBulletSize, {
// density: 0.0015, //frictionAir: 0.01, //restitution: 0,
angle: 0,
friction: 0.5,
bullet[me] = Bodies.rectangle(0, 0, 0.012 * b.modBulletSize, 0.0022 * b.modBulletSize, {
density: 0.002, //0.001 is normal
//frictionAir: 0.01, //restitution: 0,
// angle: 0,
// friction: 0.5,
frictionAir: 0,
dmg: 3 + b.modExtraDmg, //damage done in addition to the damage from momentum
classType: "bullet",
@@ -698,7 +746,7 @@ const b = {
y: mech.pos.y
})
Matter.Body.setAngle(this, mech.angle)
const speed = 80
const speed = 85
Matter.Body.setVelocity(this, {
x: mech.Vx / 2 + speed * this.charge * Math.cos(mech.angle),
y: mech.Vy / 2 + speed * this.charge * Math.sin(mech.angle)
@@ -714,6 +762,7 @@ const b = {
for (let i = 0, len = body.length; i < len; ++i) {
const SUB = Matter.Vector.sub(body[i].position, mech.pos)
const DISTANCE = Matter.Vector.magnitude(SUB)
if (DISTANCE < RANGE) {
const DEPTH = Math.max(RANGE - DISTANCE, 100)
const FORCE = Matter.Vector.mult(Matter.Vector.normalise(SUB), 0.005 * Math.sqrt(DEPTH) * Math.sqrt(body[i].mass))
@@ -732,8 +781,6 @@ const b = {
// mob[i].force.y += FORCE.y
// }
// }
} else { // charging on mouse down
mech.fireCDcycle = Infinity //can't fire until mouse is released
if (mech.crouch) {
@@ -750,7 +797,9 @@ const b = {
// if (DISTANCE < RANGE) {
// Matter.Body.setVelocity(mob[i], Matter.Vector.rotate(mob[i].velocity, 0.1))
// }
// const DRAIN = 0.0002 //&& mech.fieldMeter > DRAIN
if (DISTANCE < RANGE) {
// mech.fieldMeter -= DRAIN + mech.fieldRegen;
const DEPTH = RANGE - DISTANCE
const FORCE = Matter.Vector.mult(Matter.Vector.normalise(SUB), 0.000000001 * DEPTH * DEPTH * DEPTH * Math.sqrt(mob[i].mass))
mob[i].force.x += FORCE.x
@@ -894,7 +943,7 @@ const b = {
}
}, {
name: "wave beam", //3
description: "fire a stream of oscillating particles<br><strong style='opacity: 0.4;'>propagates through solids</strong>",
description: "fire a stream of oscillating particles<br>bullets <strong>propagate</strong> through solids",
ammo: 0,
ammoPack: 85,
have: false,
@@ -947,7 +996,7 @@ const b = {
}
}, {
name: "super balls", //4
description: "fire 3 very <strong>bouncy</strong> balls",
description: "fire balls that <strong>bounce</strong> with no momentum loss",
ammo: 0,
ammoPack: 11,
have: false,
@@ -975,7 +1024,7 @@ const b = {
}
}, {
name: "shotgun", //5
description: "fire a <strong>burst</strong> of bullets<br><em>crouch to reduce recoil</em>",
description: "fire a <strong>burst</strong> of short range bullets<br><em>crouch to reduce recoil</em>",
ammo: 0,
ammoPack: 8,
have: false,
@@ -1003,7 +1052,7 @@ const b = {
}
}, {
name: "fléchettes", //6
description: "fire accurate high speed needles",
description: "fire a flight of needles<br><strong>accurate</strong> at long range",
ammo: 0,
ammoPack: 25,
have: false,
@@ -1038,7 +1087,7 @@ const b = {
}
}, {
name: "missiles", //7
description: "fire a missile that accelerates towards nearby targets<br><span class='color-e'>explodes</span> when near target",
description: "fire missiles that accelerate towards enemies<br><strong class='color-e'>explodes</strong> when near target",
ammo: 0,
ammoPack: 8,
have: false,
@@ -1143,7 +1192,7 @@ const b = {
}
}, {
name: "flak", //8
description: "fire a cluster of short range projectiles<br><span class='color-e'>explode</span> on contact or after half a second",
description: "fire a cluster of short range projectiles<br><strong class='color-e'>explode</strong> on contact or after half a second",
ammo: 0,
ammoPack: 20,
have: false,
@@ -1186,7 +1235,7 @@ const b = {
}
}, {
name: "grenades", //9
description: "fire a projectile that <span class='color-e'>explodes</span> on contact or after one second",
description: "lob a single bouncy projectile<br><strong class='color-e'>explodes</strong> on contact or after one second",
ammo: 0,
ammoPack: 9,
have: false,
@@ -1214,7 +1263,7 @@ const b = {
}
}, {
name: "vacuum bomb", //10
description: "fire a huge <strong>bomb</strong> that sucks before it <span class='color-e'>explodes</span><br>click left mouse <strong>again</strong> to detonate",
description: "fire a bomb that <strong>sucks</strong> before <strong class='color-e'>exploding</strong><br>click left mouse again to <strong>detonate</strong>",
ammo: 0,
ammoPack: 5,
have: false,
@@ -1323,7 +1372,7 @@ const b = {
}
}, {
name: "ferro frag", //11
description: "fire a <strong>grenade</strong> that ejects <strong class='color-m'>magnetized</strong> nails<br>nails are <strong class='color-m'>attracted</strong> to enemy targets",
description: "fire a <strong>grenade</strong> that ejects magnetized nails<br>nails are <strong>attracted</strong> to enemies",
ammo: 0,
ammoPack: 8,
have: false,
@@ -1348,38 +1397,42 @@ const b = {
//target nearby mobs
const targets = []
for (let i = 0, len = mob.length; i < len; i++) {
if (mob[i].dropPowerUp) {
const sub = Matter.Vector.sub(this.position, mob[i].position);
const dist = Matter.Vector.magnitude(sub);
if (dist < 1400 &&
Matter.Query.ray(map, this.position, mob[i].position).length === 0 &&
Matter.Query.ray(body, this.position, mob[i].position).length === 0) {
targets.push(mob[i].position)
targets.push(
Matter.Vector.add(mob[i].position, Matter.Vector.mult(mob[i].velocity, dist / 60))
)
}
}
}
for (let i = 0; i < 14; i++) {
const SPEED = 35 + 20 * Math.random()
const speed = 55 + 10 * Math.random()
if (targets.length > 0) { // aim near a random target
const SPREAD = 100
const INDEX = Math.floor(Math.random() * targets.length)
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)
x: targets[index].x + SPREAD * (Math.random() - 0.5),
y: targets[index].y + SPREAD * (Math.random() - 0.5)
}
needle(this.position, Matter.Vector.mult(Matter.Vector.normalise(Matter.Vector.sub(WHERE, this.position)), SPEED))
needle(this.position, Matter.Vector.mult(Matter.Vector.normalise(Matter.Vector.sub(WHERE, this.position)), speed))
} else { // aim in random direction
const ANGLE = 2 * Math.PI * Math.random()
needle(this.position, {
x: SPEED * Math.cos(ANGLE),
y: SPEED * Math.sin(ANGLE)
x: speed * Math.cos(ANGLE),
y: speed * Math.sin(ANGLE)
})
}
function needle(pos, velocity) {
const me = bullet.length;
bullet[me] = Bodies.rectangle(pos.x, pos.y, 23 * b.modBulletSize, 2 * b.modBulletSize, b.fireAttributes(Math.atan2(velocity.y, velocity.x)));
bullet[me] = Bodies.rectangle(pos.x, pos.y, 25 * b.modBulletSize, 2 * b.modBulletSize, b.fireAttributes(Math.atan2(velocity.y, velocity.x)));
Matter.Body.setVelocity(bullet[me], velocity);
World.add(engine.world, bullet[me]); //add bullet to world
bullet[me].endCycle = game.cycle + 60 + Math.floor(15 * Math.random());
bullet[me].endCycle = game.cycle + 60 + 15 * Math.random();
// bullet[me].dmg = 1.1+b.modExtraDmg;
bullet[me].do = function () {};
}
@@ -1390,7 +1443,7 @@ const b = {
}
}, {
name: "spores", //12
description: "release an orb that discharges <span class='color-s'>spores</span> after 2 seconds<br>seeks out targets<br>passes through blocks",
description: "fire orbs that discharge <strong class='color-s'>spores</strong><br><strong class='color-s'>spores</strong> seek out enemies",
ammo: 0,
ammoPack: 5,
have: false,
@@ -1491,9 +1544,10 @@ const b = {
}
}
}, {
},
{
name: "drones", //13
description: "release <strong>drones</strong> that seek out targets for 16 seconds<br>follows mouse if no targets are found",
description: "fire <strong>drones</strong> that seek out enemies<br>follows mouse if no targets are found",
ammo: 0,
ammoPack: 20,
have: false,
@@ -1664,7 +1718,7 @@ const b = {
// },
// {
// name: "kinetic slugs", //1
// description: "fire a large <strong>rod</strong> that does excessive physical <span class='color-d'>damage</span><br><em>high recoil</em>",
// description: "fire a large <strong>rod</strong> that does excessive physical <strong class='color-d'>damage</strong><br><em>high recoil</em>",
// ammo: 0,
// ammoPack: 5,
// have: false,
@@ -1754,7 +1808,7 @@ const b = {
// {
// //draw a halo, since there will only be 1-3 balls
// name: "junk-bots", //14
// description: "release unreliable <strong>drones</strong> that defend the space around the player<br><strong>collisions</strong> may cause <span class='color-d'>malfunction</span>",
// description: "release unreliable <strong>drones</strong> that defend the space around the player<br><strong>collisions</strong> may cause <strong class='color-d'>malfunction</strong>",
// ammo: 0,
// ammoPack: 15,
// have: false,

View File

@@ -177,9 +177,10 @@ function mobCollisionChecks(event) {
}
//mob + bullet collisions
if (obj.classType === "bullet" && obj.speed > obj.minDmgSpeed) {
mob[k].foundPlayer();
// const dmg = b.dmgScale * (obj.dmg + 0.15 * obj.mass * Matter.Vector.magnitude(Matter.Vector.sub(mob[k].velocity, obj.velocity)));
const dmg = b.dmgScale * (obj.dmg + b.modExtraDmg + 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 *= 6
mob[k].foundPlayer();
mob[k].damage(dmg);
obj.onDmg(); //some bullets do actions when they hits things, like despawn
game.drawList.push({

View File

@@ -454,7 +454,9 @@ const game = {
game.startGame();
};
document.getElementById("controls").style.display = "inline";
document.getElementById("settings").style.display = "inline";
document.getElementById("build-button").style.display = "inline"
isShowingBuilds = false
// document.getElementById("settings").style.display = "inline";
document.getElementById("splash").style.display = "inline";
document.getElementById("dmg").style.display = "none";
document.getElementById("health-bg").style.display = "none";
@@ -464,8 +466,10 @@ const game = {
then: null,
startGame() {
game.onTitlePage = false;
document.body.style.overflow = "hidden"
document.getElementById("build-grid").style.display = "none"
document.getElementById("controls").style.display = "none";
document.getElementById("settings").style.display = "none";
document.getElementById("build-button").style.display = "none";
document.getElementById("splash").onclick = null; //removes the onclick effect so the function only runs once
document.getElementById("splash").style.display = "none"; //hides the element that spawned the function
document.getElementById("dmg").style.display = "inline";

View File

@@ -2,6 +2,15 @@
/* 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
@@ -12,31 +21,16 @@ gun: Spirit Bomb (singularity)
sucked in stuff increase size
uses energy
left and right click mouse icons for text displays
mod: auto pick up guns, heals, ammo
use the same rule for drones
maybe give some other bonus too?
mod: + move speed and jump height
will leg animations look strange?
that's OK for a mod
this could just slow the mobs down instead?
how?
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
mouse can get suck as clicked if the user clicks off the window
can lead to gun lock up until player pressed mouse again
should I really need to fix this?
diegetic field meter
show as the player head filling with teal color
atmosphere levels
large rotating fan that the player has to move through
give the user a rest, between combat
@@ -55,17 +49,10 @@ Boss levels
add a key that player picks up and needs to set on the exit door to open it
add modular difficulty settings
take reduced dmg
slower mob look / CD
more drops
fewer mobs
make a new var to scale number of mobs and stop using levels cleared var
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
levels spawn by having the map aspects randomly fly into place
animate new level spawn by having the map aspects randomly fly into place
new map with repeating endlessness
get ideas from Manifold Garden game
@@ -128,6 +115,37 @@ map: 0x000001 0x111111
*/
//build build grid display
let isShowingBuilds = false
document.getElementById("build-button").addEventListener("click", () => {
const el = document.getElementById("build-grid")
if (isShowingBuilds) {
el.style.display = "none"
isShowingBuilds = false
document.body.style.overflow = "hidden"
document.getElementById("controls").style.display = 'inline'
} else {
let text = ""
for (let i = 0, len = mech.fieldUpgrades.length; i < len; i++) {
text += `<div class="build-grid-module "><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 "><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 "><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"
isShowingBuilds = true
document.body.style.overflowY = "scroll";
document.body.style.overflowX = "hidden";
document.getElementById("controls").style.display = 'none'
}
});
//set up canvas
var canvas = document.getElementById("canvas");
//using "const" causes problems in safari when an ID shares the same name.

View File

@@ -14,9 +14,10 @@ const level = {
start() {
if (level.levelsCleared === 0) {
// game.difficulty = 6; //for testing to simulate possible mobs spawns
// b.giveGuns(14)
// level.startBuildRun(6)
// b.giveGuns(11)
// mech.fieldUpgrades[2].effect();
// b.giveMod(15)
// b.giveMod(20)
// spawn.pickList = ["ghoster", "ghoster"]
this.intro(); //starting level
@@ -36,6 +37,77 @@ const level = {
level.addToWorld(); //add bodies to game engine
game.draw.setPaths();
},
isBuildRun: false,
builds: [ // choose 5 total: guns, mods, and field
() => {
mech.fieldUpgrades[2].effect();
b.giveMod(6)
b.giveMod(8)
b.giveMod(9)
b.giveMod(15)
game.replaceTextLog = true;
game.makeTextLog("<h2>build: melee</h2>", 300);
},
() => {
b.giveGuns(13)
mech.fieldUpgrades[5].effect();
b.giveMod(8)
b.giveMod(3)
b.giveMod(11)
game.replaceTextLog = true;
game.makeTextLog("<h2>build: drones</h2>", 300);
},
() => {
b.giveGuns(8)
mech.fieldUpgrades[4].effect();
b.giveMod(4)
b.giveMod(5)
b.giveMod(16)
game.replaceTextLog = true;
game.makeTextLog("<h2>build: flak</h2>", 300);
},
() => {
b.giveMod(6)
b.giveMod(7)
b.giveMod(12)
b.giveMod(13)
b.giveMod(14)
game.replaceTextLog = true;
game.makeTextLog("<h2>build: block thrower</h2>", 300);
},
() => {
b.giveGuns(5)
mech.fieldUpgrades[6].effect();
b.giveMod(1)
b.giveMod(8)
b.giveMod(15)
game.replaceTextLog = true;
game.makeTextLog("<h2>build: stealth shotgun</h2>", 300);
},
() => {
b.giveGuns(2)
mech.fieldUpgrades[1].effect();
b.giveMod(8)
b.giveMod(9)
b.giveMod(11)
game.replaceTextLog = true;
game.makeTextLog("<h2>build: time out</h2>", 300);
},
() => {
b.giveGuns(0)
mech.fieldUpgrades[5].effect();
b.giveMod(7)
b.giveMod(5)
b.giveMod(18)
game.replaceTextLog = true;
game.makeTextLog("<h2>build: laser tag</h2>", 300);
},
],
startBuildRun(build) {
level.builds[build]()
game.difficulty = 6;
level.isBuildRun = true
},
difficultyIncrease(num = 1) {
for (let i = 0; i < num; i++) {
game.dmgScale += 0.2; //damage done by mobs increases each level

View File

@@ -898,6 +898,8 @@ const mobs = {
}
},
damage(dmg) {
if (b.isModLowHealthDmg) dmg *= (3 / (2 + mech.health)) //up to 50% dmg at zero player health
if (b.isModFarAwayDmg) dmg *= 1 + Math.sqrt(Math.max(1000, Math.min(3500, this.distanceToPlayer())) - 1000) * 0.01 //up to 50% dmg at max range of 3500
this.health -= dmg / Math.sqrt(this.mass);
//this.fill = this.color + this.health + ')';
if (this.health < 0.1) this.death();
@@ -913,7 +915,7 @@ const mobs = {
},
onDeath() {
// a placeholder for custom effects on mob death
//to use declare custom method in mob spawn
// to use declare custom method in mob spawn
},
leaveBody: true,
dropPowerUp: true,

View File

@@ -68,15 +68,6 @@ const mech = {
FxNotHolding: 0.015,
Fx: 0.015, //run Force on ground //this is reset in b.setModDefaults()
FxAir: 0.015, //run Force in Air
definePlayerMass(mass = mech.defaultMass) {
Matter.Body.setMass(player, mass);
//reduce air and ground move forces
this.Fx = 0.075 / mass * b.modSquirrelFx
this.FxAir = 0.375 / mass / mass
//make player stand a bit lower when holding heavy masses
this.yOffWhen.stand = Math.max(this.yOffWhen.crouch, Math.min(49, 49 - (mass - 5) * 6))
if (this.onGround && !this.crouch) this.yOffGoal = this.yOffWhen.stand;
},
yOff: 70,
yOffGoal: 70,
onGround: false, //checks if on ground or in air
@@ -415,11 +406,6 @@ const mech = {
}
},
health: 0,
// regen() {
// if (this.health < 1 && mech.cycle % 15 === 0) {
// this.addHealth(0.01);
// }
// },
drawHealth() {
if (this.health < 1) {
ctx.fillStyle = "rgba(100, 100, 100, 0.5)";
@@ -450,6 +436,12 @@ const mech = {
},
defaultFPSCycle: 0, //tracks when to return to normal fps
damage(dmg) {
if (b.isModMonogamy && b.inventory[0] === b.activeGun) {
for (let i = 0, len = b.inventory.length; i < len; i++) {
dmg *= 0.93
}
}
console.log(dmg, "after")
this.health -= dmg;
if (this.health < 0) {
this.health = 0;
@@ -639,7 +631,6 @@ const mech = {
throwChargeRate: 0,
throwChargeMax: 0,
fieldFireCD: 0,
fieldDamage: 0,
fieldShieldingScale: 0,
grabRange: 0,
fieldArc: 0,
@@ -656,7 +647,6 @@ const mech = {
player.collisionFilter.mask = 0x010011 //0x010011 is normal
this.holdingMassScale = 0.5;
this.fieldFireCD = 15;
this.fieldDamage = 0; // a value of 1.0 kills a small mob in 2-3 hits on level 1
this.fieldShieldingScale = 1; //scale energy loss after collision with mob
this.grabRange = 175;
this.fieldArc = 0.2; //run calculateFieldThreshold after setting fieldArc, used for powerUp grab and mobPush with lookingAt(mob)
@@ -701,6 +691,15 @@ const mech = {
this.throwCharge = 0;
}
},
definePlayerMass(mass = mech.defaultMass) {
Matter.Body.setMass(player, mass);
//reduce air and ground move forces
this.Fx = 0.075 / mass * b.modSquirrelFx
this.FxAir = 0.375 / mass / mass
//make player stand a bit lower when holding heavy masses
this.yOffWhen.stand = Math.max(this.yOffWhen.crouch, Math.min(49, 49 - (mass - 5) * 6))
if (this.onGround && !this.crouch) this.yOffGoal = this.yOffWhen.stand;
},
drawHold(target, stroke = true) {
const eye = 15;
const len = target.vertices.length - 1;
@@ -869,20 +868,16 @@ const mech = {
}
}
},
pushMobs() { // push all mobs in range and in direction looking
for (let i = 0, len = mob.length; i < len; ++i) {
if (this.lookingAt(mob[i]) && Matter.Vector.magnitude(Matter.Vector.sub(mob[i].position, this.pos)) < this.grabRange && Matter.Query.ray(map, mob[i].position, this.pos).length === 0) {
const fieldBlockCost = Math.max(0.02, mob[i].mass * 0.012) //0.012
pushMass(who) {
const fieldBlockCost = Math.max(0.02, who.mass * 0.012) //0.012
if (this.fieldMeter > fieldBlockCost) {
this.fieldMeter -= fieldBlockCost * this.fieldShieldingScale;
if (this.fieldMeter < 0) this.fieldMeter = 0;
if (this.fieldDamage) mob[i].damage(b.dmgScale * this.fieldDamage);
mob[i].locatePlayer();
this.drawHold(mob[i]);
//mob and player knock back
const angle = Math.atan2(player.position.y - mob[i].position.y, player.position.x - mob[i].position.x);
const mass = Math.min(Math.sqrt(mob[i].mass), 4);
Matter.Body.setVelocity(mob[i], {
this.drawHold(who);
//knock backs
const angle = Math.atan2(player.position.y - who.position.y, player.position.x - who.position.x);
const mass = Math.min(Math.sqrt(who.mass), 4);
Matter.Body.setVelocity(who, {
x: player.velocity.x - (15 * Math.cos(angle)) / mass,
y: player.velocity.y - (15 * Math.sin(angle)) / mass
});
@@ -891,34 +886,53 @@ const mech = {
y: player.velocity.y + 5 * Math.sin(angle) * mass
});
}
},
pushMobsFacing() { // find mobs in range and in direction looking
for (let i = 0, len = mob.length; i < len; ++i) {
if (
Matter.Vector.magnitude(Matter.Vector.sub(mob[i].position, this.pos)) < this.grabRange &&
this.lookingAt(mob[i]) &&
Matter.Query.ray(map, mob[i].position, this.pos).length === 0
) {
mob[i].locatePlayer();
mech.pushMass(mob[i]);
}
}
},
pushMobs360(range = this.grabRange * 0.75) { // push all mobs in range in any direction
pushMobs360(range = this.grabRange * 0.75) { // find mobs in range in any direction
for (let i = 0, len = mob.length; i < len; ++i) {
if (Matter.Vector.magnitude(Matter.Vector.sub(mob[i].position, this.pos)) < range && Matter.Query.ray(map, mob[i].position, this.pos).length === 0) {
const fieldBlockCost = Math.max(0.02, mob[i].mass * 0.012)
if (this.fieldMeter > fieldBlockCost) {
this.fieldMeter -= fieldBlockCost * this.fieldShieldingScale;
if (this.fieldMeter < 0) this.fieldMeter = 0
if (this.fieldDamage) mob[i].damage(b.dmgScale * this.fieldDamage);
if (
Matter.Vector.magnitude(Matter.Vector.sub(mob[i].position, this.pos)) < range &&
Matter.Query.ray(map, mob[i].position, this.pos).length === 0
) {
mob[i].locatePlayer();
this.drawHold(mob[i]);
//mob and player knock back
const angle = Math.atan2(player.position.y - mob[i].position.y, player.position.x - mob[i].position.x);
const mass = Math.min(Math.sqrt(mob[i].mass), 4);
// console.log(mob[i].mass, Math.sqrt(mob[i].mass), mass)
Matter.Body.setVelocity(mob[i], {
x: player.velocity.x - (15 * Math.cos(angle)) / mass,
y: player.velocity.y - (15 * Math.sin(angle)) / mass
});
Matter.Body.setVelocity(player, {
x: player.velocity.x + 5 * Math.cos(angle) * mass,
y: player.velocity.y + 5 * Math.sin(angle) * mass
});
mech.pushMass(mob[i]);
}
}
},
pushBodyFacing() { // push all body in range and in direction looking
for (let i = 0, len = body.length; i < len; ++i) {
if (
body[i].speed > 12 && body[i].mass > 2 &&
Matter.Vector.magnitude(Matter.Vector.sub(body[i].position, this.pos)) < this.grabRange &&
this.lookingAt(body[i]) &&
Matter.Query.ray(map, body[i].position, this.pos).length === 0
) {
mech.pushMass(body[i]);
}
}
},
pushBody360(range = this.grabRange * 0.75) { // push all body in range and in direction looking
for (let i = 0, len = body.length; i < len; ++i) {
if (
body[i].speed > 12 && body[i].mass > 2 &&
Matter.Vector.magnitude(Matter.Vector.sub(body[i].position, this.pos)) < range &&
this.lookingAt(body[i]) &&
Matter.Query.ray(map, body[i].position, this.pos).length === 0 &&
body[i].collisionFilter.category === 0x010000
) {
mech.pushMass(body[i]);
}
}
},
lookForPickUp(range = this.grabRange) { //find body to pickup
@@ -1017,12 +1031,12 @@ const mech = {
},
fieldUpgrades: [{
name: "field emitter",
description: "<strong class='color-f'>shields</strong> you from <span class='color-d'>damage</span><br>lets you <strong>pick up</strong> and throw objects",
description: "use <strong class='color-f'>energy</strong> to <strong>shield</strong> yourself from <strong class='color-d'>damage</strong><br>lets you <strong>pick up</strong> and <strong>throw</strong> objects",
effect: () => {
mech.fieldMode = 0;
mech.fieldText();
game.replaceTextLog = true; //allow text over write
// game.makeTextLog("<strong style='font-size:30px;'></strong><br> <span class='faded'>(right click or space bar)</span><p></p>", 1200);
// game.makeTextLog("<strong style='font-size:30px;'></strong><br> <strong class='faded'>(right click or space bar)</strong><p></p>", 1200);
mech.setHoldDefaults();
mech.hold = function () {
if (mech.isHolding) {
@@ -1032,7 +1046,8 @@ const mech = {
} else if ((keys[32] || game.mouseDownRight && mech.fieldMeter > 0.1)) { //not hold but field button is pressed
mech.drawField();
mech.grabPowerUp();
mech.pushMobs();
mech.pushMobsFacing();
mech.pushBodyFacing();
mech.lookForPickUp();
} else if (mech.holdingTarget && mech.fireCDcycle < mech.cycle && mech.fieldMeter > 0.05) { //holding, but field button is released
mech.pickUp();
@@ -1045,7 +1060,7 @@ const mech = {
},
{
name: "time dilation field",
description: "<strong style='letter-spacing: 3px;'>stop time</strong> while field is active<br> <em>can fire while field is active</em>",
description: "use <strong class='color-f'>energy</strong> to <strong style='letter-spacing: 1px;'>stop time</strong><br><em>can fire bullets while field is active</em>",
effect: () => {
mech.fieldMode = 1;
mech.fieldText();
@@ -1119,14 +1134,14 @@ const mech = {
},
{
name: "plasma torch",
description: "field emits a beam of destructive <strong style='color:#d0d;'>ionized gas</strong><br><span style='color:#a00;'>decreased</span> <strong class='color-f'>shield</strong> range and efficiency",
description: "use <strong class='color-f'>energy</strong> to emit <strong class='color-d'>damaging</strong> beam<br><strong>decreased</strong> <strong>shield</strong> range and efficiency",
effect: () => {
mech.fieldMode = 2;
mech.fieldText();
mech.setHoldDefaults();
// mech.fieldShieldingScale = 2;
// mech.grabRange = 125;
mech.fieldArc = 0.05 //run calculateFieldThreshold after setting fieldArc, used for powerUp grab and mobPush with lookingAt(mob)
mech.fieldArc = 0.1 //run calculateFieldThreshold after setting fieldArc, used for powerUp grab and mobPush with lookingAt(mob)
mech.calculateFieldThreshold(); //run after setting fieldArc, used for powerUp grab and mobPush with lookingAt(mob)
mech.hold = function () {
if (mech.isHolding) {
@@ -1269,7 +1284,8 @@ const mech = {
ctx.lineWidth = 2 * Math.random();
ctx.stroke();
mech.pushMobs360(100);
mech.pushMobs360(110);
// mech.pushBody360(100); //disabled because doesn't work at short range
mech.grabPowerUp();
mech.lookForPickUp();
} else {
@@ -1286,7 +1302,7 @@ const mech = {
},
{
name: "negative mass field",
description: "field nullifies &nbsp;<strong style='letter-spacing: 15px;'>gravity</strong><br><em>can fire while field is active</em>",
description: "use <strong class='color-f'>energy</strong> to nullify &nbsp; <strong style='letter-spacing: 10px;'>gravity</strong><br><em>can fire bullets while active</em>",
effect: () => {
mech.fieldMode = 3;
mech.fieldText();
@@ -1302,6 +1318,7 @@ const mech = {
const DRAIN = 0.0004
if (mech.fieldMeter > DRAIN) {
mech.pushMobs360(170);
mech.pushBody360(180);
mech.grabPowerUp();
mech.lookForPickUp(170);
//look for nearby objects to make zero-g
@@ -1373,7 +1390,7 @@ const mech = {
},
{
name: "standing wave harmonics",
description: "you are surrounded by oscillating <strong class='color-f'>shields</strong><br> <span style='color:#a00;'>decreased</span> field regeneration",
description: "oscillating <strong>shields</strong> surround you <strong>constantly</strong><br> <strong>decreased</strong> <strong class='color-f'>energy</strong> regeneration",
effect: () => {
mech.fieldMode = 4;
mech.fieldText();
@@ -1409,6 +1426,7 @@ const mech = {
ctx.arc(mech.pos.x, mech.pos.y, grabRange3, 0, 2 * Math.PI);
ctx.fill();
mech.pushMobs360(netGrabRange);
mech.pushBody360(netGrabRange);
}
mech.drawFieldMeter()
}
@@ -1416,16 +1434,16 @@ const mech = {
},
{
name: "nano-scale manufacturing",
description: "excess field <span class='color-f'>energy</span> used to build <strong class='color-b'>drones</strong><br> increased <span class='color-f'>energy</span> regeneration",
description: "excess <strong class='color-f'>energy</strong> used to build <strong>drones</strong><br><strong>3x</strong> <strong class='color-f'>energy</strong> regeneration",
effect: () => {
let gunIndex = 13 //Math.random() < 0.5 ? 13 : 14
mech.fieldMode = 5;
mech.fieldText();
mech.setHoldDefaults();
mech.fieldRegen *= 3.5;
mech.fieldRegen *= 3;
mech.hold = function () {
if (mech.fieldMeter === 1) {
mech.fieldMeter -= 0.5;
mech.fieldMeter -= 0.43;
b.guns[gunIndex].fire() //spawn drone
}
if (mech.isHolding) {
@@ -1433,7 +1451,8 @@ const mech = {
mech.holding();
mech.throw();
} else if ((keys[32] || game.mouseDownRight && mech.fieldMeter > 0.1)) { //not hold but field button is pressed
mech.pushMobs();
mech.pushMobsFacing();
mech.pushBodyFacing();
mech.drawField();
mech.grabPowerUp();
mech.lookForPickUp();
@@ -1448,7 +1467,7 @@ const mech = {
},
{
name: "phase decoherence field",
description: "<strong>intangible</strong> while field is active<br><em style='opacity: 0.6;'>can't see or be seen outside field</em>",
description: "use <strong class='color-f'>energy</strong> to to become <strong>intangible</strong><br><em style='opacity: 0.6;'>can't see or be seen outside field</em>",
effect: () => {
mech.fieldMode = 6;
mech.fieldText();
@@ -1493,142 +1512,5 @@ const mech = {
}
}
},
// {
// name: "electrostatic field",
// description: "field does <strong class='color-d'>damage</strong> on contact<br> increased <span class='color-f'>field</span> regeneration",
// effect: () => {
// mech.fieldMode = 2;
// mech.fieldText();
// mech.setHoldDefaults();
// mech.grabRange = 225;
// mech.fieldShieldingScale = 2.5;
// mech.fieldRegen *= 2;
// mech.fieldDamage = 4; //passive field does extra damage
// // mech.fieldArc = 0.11
// // mech.calculateFieldThreshold(); //run after setting fieldArc, used for powerUp grab and mobPush with lookingAt(mob)
// mech.hold = function () {
// if (mech.isHolding) {
// mech.drawHold(mech.holdingTarget);
// mech.holding();
// mech.throw();
// } else if ((keys[32] || game.mouseDownRight) && mech.fieldMeter > 0.15) { //not hold but field button is pressed
// //draw electricity
// const Dx = Math.cos(mech.angle);
// const Dy = Math.sin(mech.angle);
// let x = mech.pos.x + 20 * Dx;
// let y = mech.pos.y + 20 * Dy;
// ctx.beginPath();
// ctx.moveTo(x, y);
// for (let i = 0; i < 8; i++) {
// x += 18 * (Dx + 2 * (Math.random() - 0.5))
// y += 18 * (Dy + 2 * (Math.random() - 0.5))
// ctx.lineTo(x, y);
// }
// ctx.lineWidth = 1 //0.5 + 2 * Math.random();
// ctx.strokeStyle = `rgba(100,20,50,${0.5+0.5*Math.random()})`;
// ctx.stroke();
// //draw field
// const range = 170;
// const arc = Math.PI * 0.11
// ctx.beginPath();
// ctx.arc(mech.pos.x, mech.pos.y, range, mech.angle - arc, mech.angle + arc, false);
// ctx.lineTo(mech.pos.x + 13 * Math.cos(mech.angle), mech.pos.y + 13 * Math.sin(mech.angle));
// if (mech.holdingTarget) {
// ctx.fillStyle = "rgba(255,50,150," + (0.01 + mech.fieldMeter * (0.1 + 0.1 * Math.random())) + ")";
// } else {
// ctx.fillStyle = "rgba(255,50,150," + (0.02 + mech.fieldMeter * (0.18 + 0.18 * Math.random())) + ")";
// }
// // ctx.fillStyle = "rgba(110,170,200," + (0.02 + mech.fieldMeter * (0.08 + 0.1 * Math.random())) + ")";
// // ctx.fillStyle = "rgba(110,170,200," + (0.06 + mech.fieldMeter * (0.1 + 0.18 * Math.random())) + ")";
// ctx.fill();
// //draw random lines in field for cool effect
// // eye = 15;
// // ctx.beginPath();
// // ctx.moveTo(mech.pos.x + eye * Math.cos(mech.angle), mech.pos.y + eye * Math.sin(mech.angle));
// // const offAngle = mech.angle + 2 * Math.PI * mech.fieldArc * (Math.random() - 0.5);
// // ctx.lineTo(mech.pos.x + range * Math.cos(offAngle), mech.pos.y + range * Math.sin(offAngle));
// // ctx.strokeStyle = "rgba(100,20,50,0.2)";
// // ctx.stroke();
// mech.grabPowerUp();
// mech.pushMobs();
// mech.lookForPickUp();
// } else if (mech.holdingTarget && mech.fireCDcycle < mech.cycle && mech.fieldMeter > 0.05) { //holding, but field button is released
// mech.pickUp();
// } else {
// mech.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists)
// }
// mech.drawFieldMeter()
// }
// }
// },
// () => {
// mech.fieldMode = 7;
// game.makeTextLog("<strong style='font-size:30px;'>Thermal Radiation Field</strong><br> <span class='faded'>(right click or space bar)</span> <p>field grows while active<br>damages all targets within range, <span style='color:#a00;'>including player</span><br> <span style='color:#a00;'>decreased</span> field shielding efficiency</p>", 1200);
// mech.setHoldDefaults();
// mech.fieldShieldingScale = 10;
// mech.rangeSmoothing = 0
// mech.hold = function () {
// if (mech.isHolding) {
// mech.drawHold(mech.holdingTarget);
// mech.holding();
// mech.throw();
// } else if ((keys[32] || game.mouseDownRight && mech.fieldCDcycle < mech.cycle)) { //not hold but field button is pressed
// mech.grabPowerUp();
// mech.lookForPickUp(Math.max(180, mech.grabRange));
// mech.pushMobs360(140);
// if (mech.health > 0.1) {
// const DRAIN = 0.0008
// if (mech.fieldMeter > DRAIN) {
// mech.fieldMeter -= DRAIN;
// mech.damage(0.00005 + 0.00000012 * mech.grabRange)
// //draw damage field
// mech.grabRange = mech.grabRange * 0.997 + (1350 + 150 * Math.cos(mech.cycle / 30)) * 0.003
// let gradient = ctx.createRadialGradient(this.pos.x, this.pos.y, 0, this.pos.x, this.pos.y, mech.grabRange);
// gradient.addColorStop(0, 'rgba(255,255,255,0.7)');
// gradient.addColorStop(1, 'rgba(255,0,50,' + (0.6 + 0.2 * Math.random()) + ')');
// const angleOff = 2 * Math.PI * Math.random()
// ctx.beginPath();
// ctx.arc(this.pos.x, this.pos.y, mech.grabRange + Math.sqrt(mech.grabRange) * 0.7 * (Math.random() - 0.5), angleOff, 1.8 * Math.PI + angleOff);
// ctx.fillStyle = gradient //rgba(255,0,0,0.2)
// ctx.fill();
// //damage and push away mobs in range
// for (let i = 0, len = mob.length; i < len; ++i) {
// if (mob[i].alive) {
// sub = Matter.Vector.sub(this.pos, mob[i].position);
// dist = Matter.Vector.magnitude(sub);
// if (dist < mech.grabRange) {
// mob[i].damage(0.01);
// mob[i].locatePlayer();
// mob[i].force = Matter.Vector.mult(Matter.Vector.normalise(sub), -0.0001 * mob[i].mass) //gently push mobs back
// }
// }
// }
// } else {
// mech.fieldCDcycle = mech.cycle + 120;
// }
// } else {
// mech.grabRange = 180;
// mech.drawField();
// mech.grabPowerUp();
// mech.lookForPickUp();
// }
// } else if (mech.holdingTarget && mech.fireCDcycle < mech.cycle && mech.fieldMeter > 0.05) { //holding, but field button is released
// mech.grabRange = 0
// mech.pickUp();
// } else {
// mech.grabRange = 0
// mech.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists)
// }
// mech.drawFieldMeter()
// }
// },
],
};

View File

@@ -45,7 +45,8 @@ const powerUps = {
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
const ammo = Math.ceil((target.ammoPack * (0.45 + 0.08 * Math.random())) / b.dmgScale);
let ammo = Math.ceil((target.ammoPack * (0.4 + 0.05 * Math.random())) / b.dmgScale);
if (level.isBuildRun) ammo *= 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);
@@ -143,38 +144,49 @@ const powerUps = {
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) {
if (b.inventory.length > 0) powerUps.spawn(x, y, "ammo");
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 * (5 - 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 * (8 - 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.042 * (b.mods.length - b.modCount)) {
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.05 * (7 - 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")
} 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
@@ -195,6 +207,7 @@ const powerUps = {
}
},
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();
@@ -221,5 +234,6 @@ const powerUps = {
});
}
World.add(engine.world, powerUp[i]); //add to world
}
},
};

113
style.css
View File

@@ -1,7 +1,7 @@
body {
font-family: "Helvetica", "Arial", sans-serif;
margin: 0;
overflow: hidden;
/* overflow: hidden; */
background-color: #fff;
user-select: none;
/*cursor: crosshair;*/
@@ -35,10 +35,78 @@ table {
/* background-color: #ddd; */
}
th {
text-align: left;
}
summary {
font-size: 1.2em;
}
#build-button {
position: absolute;
bottom: 0px;
right: 1px;
z-index: 12;
font-size: 1.3em;
}
#build-grid {
padding: 10px;
margin: 0px;
border: 0px;
/* border-radius: 8px; */
background-color: #b6bfca;
display: none;
/* display: grid; */
grid-template-columns: repeat(auto-fit, minmax(292px, 1fr));
grid-auto-rows: minmax(auto, auto);
grid-gap: 15px;
position: relative;
bottom: 0px;
/* left: 0px; */
z-index: 12;
font-size: 1.3em;
}
.build-grid-module {
/* box-shadow: 0px 1px 4px #234; */
padding: 7px;
/* margin: 4px; */
line-height: 150%;
border-radius: 6px;
background: #eee;
font-size: 0.65em;
/* display: flex; */
}
.build-grid-module:hover {
background-color: #fff;
}
.gun-module {
background: #d5dde5;
}
.field-module {
background: #bde;
}
.mod-module {
background: #fdf;
}
/* #build {
position: absolute;
bottom: 0px;
right: 1px;
z-index: 12;
font-size: 1.3em;
} */
#controls {
position: absolute;
bottom: 0px;
@@ -49,14 +117,6 @@ summary {
/* border-radius: 5px; */
}
#settings {
position: absolute;
bottom: 0px;
right: 1px;
z-index: 12;
font-size: 1.3em;
}
#details-div {
padding: 10px;
border-radius: 8px;
@@ -214,36 +274,28 @@ em {
.color-f {
color: #0cf;
}
.color-b {
color: #024;
letter-spacing: 1px;
}
.color-d {
color: #f05;
}
.color-l {
color: #f0f;
color: #f03;
letter-spacing: 1px;
}
.color-h {
color: #0d9;
color: #0c8;
letter-spacing: 1px;
}
.color-e {
color: #a10;
}
.color-m {
color: #536;
color: #e50;
letter-spacing: 1px;
}
.color-s {
color: #066;
font-weight: 900;
letter-spacing: 2px;
letter-spacing: 1px;
}
.faded {
@@ -256,6 +308,15 @@ em {
height: 20px;
border-radius: 50%;
display: inline-block;
margin-bottom: -2px;
}
.circle-grid {
width: 20px;
height: 20px;
border-radius: 50%;
display: inline-block;
margin-bottom: -4px;
}
.field {
@@ -268,12 +329,10 @@ em {
.gun {
background: #149;
margin-bottom: -2px;
}
.heal {
background: #0d9;
margin-bottom: -2px;
}
.box {