added plasma field, removed electrostatic field, added throwing mod
This commit is contained in:
27
index.html
27
index.html
@@ -150,26 +150,25 @@
|
||||
<details>
|
||||
<summary>settings</summary>
|
||||
<div id="details-div">
|
||||
<label for="fps-select">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>
|
||||
<!-- <option value="15">15 fps cap</option> -->
|
||||
</select>
|
||||
<label for="body-damage" title="allow damage from heavy, fast moving blocks">damage from blocks:</label>
|
||||
<input type="checkbox" id="body-damage" name="body-damage" checked>
|
||||
<br><br>
|
||||
<label for="difficulty-select">combat difficulty:</label>
|
||||
<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="falling-damage">falling damage:</label>
|
||||
<input type="checkbox" id="falling-damage" name="falling-damage" checked> -->
|
||||
<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>
|
||||
@@ -264,6 +263,8 @@
|
||||
<!-- mouse -->
|
||||
<g class="draw-lines3" transform="translate(290,430) scale(0.28)" stroke-linecap="round" stroke-linejoin="round" stroke-width="10px" stroke="#222" fill="none">
|
||||
<path class="fade-in" d="M832.41,106.64 V323.55 H651.57 V256.64 c0-82.5,67.5-150,150-150 Z" fill="rgb(0, 200, 255)" stroke="none" />
|
||||
<!-- <path class="fade-in" d="M832.41,106.64 V323.55 H651.57 V256.64 c0-82.5,67.5-150,150-150 Z" fill="#789" stroke="none" />
|
||||
<path class="fade-in" d="M827,112 h30 a140,140,0,0,1,140,140 v68 h-167 z" fill="#7ce" stroke="none" /> -->
|
||||
<path d="M827,112 h30 a140,140,0,0,1,140,140 v268 a140,140,0,0,1-140,140 h-60 a140,140,0,0,1-140-140v-268 a140,140,0,0,1,140-140h60" />
|
||||
<path d="M657 317 h 340 h-170 v-207 s 21 -59, -5 -59 S 807 7, 807 7" />
|
||||
<ellipse fill="#fff" cx="827.57" cy="218.64" rx="29" ry="68" />
|
||||
|
||||
172
js/bullets.js
172
js/bullets.js
@@ -35,6 +35,8 @@ const b = {
|
||||
b.extraDmg = 0;
|
||||
b.annihilation = false;
|
||||
b.fullHeal = false;
|
||||
mech.throwChargeRate = 2;
|
||||
mech.throwChargeMax = 50;
|
||||
for (let i = 0; i < b.mods.length; i++) {
|
||||
b.mods[i].have = false;
|
||||
}
|
||||
@@ -148,13 +150,23 @@ const b = {
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "superconductive healing",
|
||||
name: "recursive healing",
|
||||
description: "<span class='color-h'>heals</span> bring you to full health",
|
||||
have: false, //13
|
||||
effect: () => { // good with ablative synthesis, electrostatic field
|
||||
b.fullHeal = true
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "superconductive rail gun",
|
||||
description: "throw blocks at very high speeds<br><em>to charge a throw, hold right click while holding a block<br>release right click to fire</em>",
|
||||
have: false, //14
|
||||
effect: () => { // good with ablative synthesis, electrostatic field
|
||||
b.fullHeal = true
|
||||
mech.throwChargeRate = 4;
|
||||
mech.throwChargeMax = 150;
|
||||
}
|
||||
},
|
||||
],
|
||||
giveMod(i) {
|
||||
b.mods[i].effect(); //give specific mod
|
||||
@@ -787,21 +799,20 @@ const b = {
|
||||
},
|
||||
{
|
||||
name: "fléchettes", //6
|
||||
description: "fire accurate high speed needles<br>crouch to fire 6 needles at once",
|
||||
description: "fire accurate high speed needles",
|
||||
ammo: 0,
|
||||
ammoPack: 35,
|
||||
ammoPack: 20,
|
||||
have: false,
|
||||
isStarterGun: true,
|
||||
fire() {
|
||||
function spawnFlechette(dir = mech.angle, speed, size = 1) {
|
||||
const me = bullet.length;
|
||||
bullet[me] = Bodies.rectangle(mech.pos.x + 40 * Math.cos(dir), mech.pos.y + 40 * Math.sin(dir), 36 * size * b.modBulletSize, 2.5 * size * b.modBulletSize, b.fireAttributes(dir));
|
||||
bullet[me] = Bodies.rectangle(mech.pos.x + 40 * Math.cos(dir), mech.pos.y + 40 * Math.sin(dir), 65 * size * b.modBulletSize, 1.5 * size * b.modBulletSize, b.fireAttributes(dir));
|
||||
bullet[me].endCycle = game.cycle + Math.floor(180 * b.modBulletsLastLonger);
|
||||
bullet[me].dmg = 0.5 * size + b.extraDmg;
|
||||
bullet[me].dmg = 0.25 * size + b.extraDmg;
|
||||
b.drawOneBullet(bullet[me].vertices);
|
||||
bullet[me].do = function () {
|
||||
//low gravity
|
||||
this.force.y += this.mass * 0.0002;
|
||||
this.force.y += this.mass * 0.0002; //low gravity
|
||||
};
|
||||
Matter.Body.setVelocity(bullet[me], {
|
||||
x: mech.Vx / 2 + speed * Math.cos(dir),
|
||||
@@ -811,15 +822,13 @@ const b = {
|
||||
}
|
||||
|
||||
if (mech.crouch) {
|
||||
mech.fireCDcycle = mech.cycle + Math.floor(60 * b.modFireRate); // cool down
|
||||
// b.guns[6].ammo -= b.modNoAmmo ? Math.floor(COST / 2) : COST
|
||||
for (let i = 0; i < 6; i++) {
|
||||
spawnFlechette(mech.angle + 0.14 * (Math.random() - 0.5), 30 + 6 * Math.random(), 0.7)
|
||||
}
|
||||
spawnFlechette(mech.angle, 55, 1.2)
|
||||
} else {
|
||||
mech.fireCDcycle = mech.cycle + Math.floor(30 * b.modFireRate); // cool down
|
||||
spawnFlechette(mech.angle, 45)
|
||||
for (let i = 0; i < 7; i++) {
|
||||
spawnFlechette(mech.angle + 0.14 * (Math.random() - 0.5), 30 + 8 * Math.random(), 0.5)
|
||||
}
|
||||
}
|
||||
mech.fireCDcycle = mech.cycle + Math.floor(30 * b.modFireRate); // cool down
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -1454,140 +1463,5 @@ const b = {
|
||||
b.drawOneBullet(bullet[me].vertices);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "short range laser", //15
|
||||
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",
|
||||
ammo: 0,
|
||||
ammoPack: Infinity,
|
||||
have: false,
|
||||
isStarterGun: true,
|
||||
fire() {
|
||||
//laser drains energy as well as bullets
|
||||
const FIELD_DRAIN = 0.001
|
||||
const damage = 0.3
|
||||
if (mech.fieldMeter < FIELD_DRAIN) {
|
||||
mech.fireCDcycle = mech.cycle + 100; // cool down if out of energy
|
||||
} else {
|
||||
mech.fieldMeter -= mech.fieldRegen + FIELD_DRAIN
|
||||
let best;
|
||||
const color = "#f06";
|
||||
const range = 150 + 200 * Math.random() //+ 100 * Math.sin(mech.cycle * 0.3);
|
||||
const dir = mech.angle // + 0.04 * (Math.random() - 0.5)
|
||||
const path = [{
|
||||
x: mech.pos.x + 20 * Math.cos(dir),
|
||||
y: mech.pos.y + 20 * Math.sin(dir)
|
||||
},
|
||||
{
|
||||
x: mech.pos.x + range * Math.cos(dir),
|
||||
y: mech.pos.y + range * Math.sin(dir)
|
||||
}
|
||||
];
|
||||
const vertexCollision = function (v1, v1End, domain) {
|
||||
for (let i = 0; i < domain.length; ++i) {
|
||||
let vertices = domain[i].vertices;
|
||||
const len = vertices.length - 1;
|
||||
for (let j = 0; j < len; j++) {
|
||||
results = game.checkLineIntersection(v1, v1End, vertices[j], vertices[j + 1]);
|
||||
if (results.onLine1 && results.onLine2) {
|
||||
const dx = v1.x - results.x;
|
||||
const dy = v1.y - results.y;
|
||||
const dist2 = dx * dx + dy * dy;
|
||||
if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) {
|
||||
best = {
|
||||
x: results.x,
|
||||
y: results.y,
|
||||
dist2: dist2,
|
||||
who: domain[i],
|
||||
v1: vertices[j],
|
||||
v2: vertices[j + 1]
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
results = game.checkLineIntersection(v1, v1End, vertices[0], vertices[len]);
|
||||
if (results.onLine1 && results.onLine2) {
|
||||
const dx = v1.x - results.x;
|
||||
const dy = v1.y - results.y;
|
||||
const dist2 = dx * dx + dy * dy;
|
||||
if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) {
|
||||
best = {
|
||||
x: results.x,
|
||||
y: results.y,
|
||||
dist2: dist2,
|
||||
who: domain[i],
|
||||
v1: vertices[0],
|
||||
v2: vertices[len]
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
const checkforCollisions = function () {
|
||||
best = {
|
||||
x: null,
|
||||
y: null,
|
||||
dist2: Infinity,
|
||||
who: null,
|
||||
v1: null,
|
||||
v2: null
|
||||
};
|
||||
vertexCollision(path[path.length - 2], path[path.length - 1], mob);
|
||||
vertexCollision(path[path.length - 2], path[path.length - 1], map);
|
||||
vertexCollision(path[path.length - 2], path[path.length - 1], body);
|
||||
};
|
||||
const laserHitMob = function (dmg) {
|
||||
if (best.who.alive) {
|
||||
dmg *= b.dmgScale * damage;
|
||||
best.who.damage(dmg);
|
||||
best.who.locatePlayer();
|
||||
//draw mob damage circle
|
||||
ctx.fillStyle = color;
|
||||
ctx.beginPath();
|
||||
ctx.arc(path[path.length - 1].x, path[path.length - 1].y, Math.sqrt(dmg) * 100, 0, 2 * Math.PI);
|
||||
ctx.fill();
|
||||
}
|
||||
};
|
||||
checkforCollisions();
|
||||
if (best.dist2 != Infinity) {
|
||||
//if hitting something
|
||||
path[path.length - 1] = {
|
||||
x: best.x,
|
||||
y: best.y
|
||||
};
|
||||
laserHitMob(1);
|
||||
}
|
||||
ctx.strokeStyle = color;
|
||||
ctx.lineWidth = 1
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(path[0].x, path[0].y);
|
||||
ctx.lineTo(path[1].x, path[1].y);
|
||||
ctx.stroke();
|
||||
ctx.strokeStyle = "rgba(255,0,60,0.1)"
|
||||
ctx.lineWidth = 10
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(path[0].x, path[0].y);
|
||||
ctx.lineTo(path[1].x, path[1].y);
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
},
|
||||
// {
|
||||
// name: "melee", //15
|
||||
// description: "rapidly fire a stream of short range <strong>bullets</strong>",
|
||||
// ammo: 0,
|
||||
// ammoPack: 205,
|
||||
// have: false,
|
||||
// isStarterGun: true,
|
||||
// fire() {
|
||||
// const me = bullet.length;
|
||||
// const dir = mech.angle + (Math.random() - 0.5) * ((mech.crouch) ? 0.1 : 0.7);
|
||||
// bullet[me] = Bodies.rectangle(mech.pos.x + 30 * Math.cos(mech.angle), mech.pos.y + 30 * Math.sin(mech.angle), 12 * b.modBulletSize, 12 * b.modBulletSize, b.fireAttributes(dir));
|
||||
// b.fireProps(mech.crouch ? 6 : 2, mech.crouch ? 30 : 20, dir, me); //cd , speed
|
||||
// bullet[me].endCycle = game.cycle + Math.floor(18 * b.modBulletsLastLonger);
|
||||
// bullet[me].do = function () {
|
||||
|
||||
// };
|
||||
// }
|
||||
// },
|
||||
]
|
||||
};
|
||||
@@ -78,7 +78,7 @@ function mobCollisionChecks(event) {
|
||||
for (let i = 0, j = pairs.length; i != j; i++) {
|
||||
|
||||
//body + player collision
|
||||
if (mech.damageImmune < mech.cycle) {
|
||||
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) {
|
||||
|
||||
@@ -75,6 +75,7 @@ const game = {
|
||||
lastTimeStamp: 0, //tracks time stamps for measuring delta
|
||||
delta: 1000 / 60, //speed of game engine //looks like it has to be 16 to match player input
|
||||
buttonCD: 0,
|
||||
isBodyDamage: true,
|
||||
isEasyMode: false,
|
||||
difficulty: null,
|
||||
// dropFPS(cap = 40, time = 15) {
|
||||
@@ -418,6 +419,7 @@ const game = {
|
||||
mech.addHealth(1);
|
||||
mech.alive = true;
|
||||
level.onLevel = 0;
|
||||
level.levelsCleared = 0;
|
||||
|
||||
//resetting difficulty
|
||||
game.dmgScale = 1;
|
||||
@@ -434,7 +436,6 @@ const game = {
|
||||
level.difficultyIncrease(game.difficulty)
|
||||
}
|
||||
|
||||
|
||||
game.clearNow = true;
|
||||
document.getElementById("text-log").style.opacity = 0;
|
||||
document.getElementById("fade-out").style.opacity = 0;
|
||||
|
||||
@@ -174,7 +174,7 @@ document.body.addEventListener("wheel", (e) => {
|
||||
passive: true
|
||||
});
|
||||
|
||||
document.getElementById("fps-select").addEventListener("input", event => {
|
||||
document.getElementById("fps-select").addEventListener("input", () => {
|
||||
let value = document.getElementById("fps-select").value
|
||||
if (value === 'max') {
|
||||
game.fpsCapDefault = 999999999;
|
||||
@@ -191,6 +191,10 @@ document.getElementById("fps-select").addEventListener("input", event => {
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById("body-damage").addEventListener("input", () => {
|
||||
game.isBodyDamage = document.getElementById("body-damage").checked
|
||||
});
|
||||
|
||||
// function playSound(id) {
|
||||
// //play sound
|
||||
// if (false) {
|
||||
|
||||
10
js/level.js
10
js/level.js
@@ -10,11 +10,12 @@ const level = {
|
||||
boostScale: 0.000023,
|
||||
levels: ["skyscrapers", "rooftops", "warehouse", "highrise", "office", "aerie"],
|
||||
onLevel: 0,
|
||||
levelsCleared: 0,
|
||||
start() {
|
||||
if (level.onLevel === 0) {
|
||||
if (level.levelsCleared === 0) {
|
||||
// game.difficulty = 6; //for testing to simulate possible mobs spawns
|
||||
b.giveGuns(15)
|
||||
// mech.fieldUpgrades[6].effect();
|
||||
// b.giveGuns(6)
|
||||
// mech.fieldUpgrades[7].effect();
|
||||
// b.giveMod(13)
|
||||
// spawn.pickList = ["ghoster", "ghoster"]
|
||||
|
||||
@@ -1470,6 +1471,7 @@ const level = {
|
||||
game.difficulty++;
|
||||
if (game.difficulty > 1) level.difficultyIncrease()
|
||||
//cycles map to next level
|
||||
level.levelsCleared++;
|
||||
level.onLevel++;
|
||||
if (level.onLevel > level.levels.length - 1) level.onLevel = 0;
|
||||
|
||||
@@ -1566,7 +1568,7 @@ const level = {
|
||||
}
|
||||
},
|
||||
levelAnnounce() {
|
||||
document.title = "n-gon: L" + (level.onLevel) + " " + level.levels[level.onLevel];
|
||||
document.title = "n-gon: L" + (level.levelsCleared) + " " + level.levels[level.onLevel];
|
||||
// game.makeTextLog(`<div style='font-size: 25px;'>level ${game.difficulty} </div> <div style='font-size: 32px;'>${level.levels[level.onLevel]} </div>`, 300);
|
||||
// if (game.difficulty === 0) text = "";
|
||||
// text = "Level " + (game.difficulty + 1) + ": " + spawn.pickList[0] + "s + " + spawn.pickList[1] + "s";
|
||||
|
||||
287
js/player.js
287
js/player.js
@@ -711,14 +711,12 @@ const mech = {
|
||||
this.isStealth = false;
|
||||
player.collisionFilter.mask = 0x010011 //0x010011 is normal
|
||||
this.holdingMassScale = 0.5;
|
||||
this.throwChargeRate = 2;
|
||||
this.throwChargeMax = 50;
|
||||
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;
|
||||
this.calculateFieldThreshold();
|
||||
this.fieldArc = 0.2; //run calculateFieldThreshold after setting fieldArc, used for powerUp grab and mobPush with lookingAt(mob)
|
||||
this.calculateFieldThreshold(); //run calculateFieldThreshold after setting fieldArc, used for powerUp grab and mobPush with lookingAt(mob)
|
||||
this.jumpForce = 0.38;
|
||||
this.Fx = 0.015; //run Force on ground
|
||||
this.FxAir = 0.015; //run Force in Air
|
||||
@@ -802,8 +800,8 @@ const mech = {
|
||||
},
|
||||
throw () {
|
||||
if ((keys[32] || game.mouseDownRight)) {
|
||||
if (this.fieldMeter > 0.002) {
|
||||
this.fieldMeter -= 0.002;
|
||||
if (this.fieldMeter > 0.0008) {
|
||||
this.fieldMeter -= 0.0008;
|
||||
this.throwCharge += this.throwChargeRate;;
|
||||
//draw charge
|
||||
const x = mech.pos.x + 15 * Math.cos(this.angle);
|
||||
@@ -1127,9 +1125,12 @@ const mech = {
|
||||
mech.fieldMeter -= DRAIN;
|
||||
|
||||
//draw field everywhere
|
||||
ctx.fillStyle = "rgba(110,170,200," + (0.19 + 0.16 * Math.random()) + ")";
|
||||
ctx.fillRect(-100000, -100000, 200000, 200000)
|
||||
|
||||
ctx.globalCompositeOperation = "saturation"
|
||||
// ctx.fillStyle = "rgba(100,200,230," + (0.25 + 0.06 * Math.random()) + ")";
|
||||
ctx.fillStyle = "#ccc";
|
||||
ctx.fillRect(-100000, -100000, 200000, 200000)
|
||||
ctx.globalCompositeOperation = "source-over"
|
||||
//stop time
|
||||
mech.isBodiesAsleep = true;
|
||||
|
||||
@@ -1177,70 +1178,163 @@ const mech = {
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "electrostatic field",
|
||||
description: "field does <strong class='color-d'>damage</strong> on contact<br> blocks are thrown at a higher velocity<br> increased <span class='color-f'>field</span> regeneration",
|
||||
name: "plasma torch",
|
||||
description: "field emits a beam of destructive <span style='color:#f0f;'>ionized gas</span><br><span style='color:#a00;'>decreased</span> <strong style='color: #08f;'>shield</strong> range and efficiency",
|
||||
effect: () => {
|
||||
mech.fieldMode = 2;
|
||||
mech.fieldText();
|
||||
mech.setHoldDefaults();
|
||||
//throw quicker and harder
|
||||
mech.grabRange = 225;
|
||||
mech.fieldShieldingScale = 2;
|
||||
mech.fieldRegen *= 2;
|
||||
mech.throwChargeRate = 3;
|
||||
mech.throwChargeMax = 140;
|
||||
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.fieldShieldingScale = 2;
|
||||
mech.grabRange = 125;
|
||||
mech.fieldArc = 0.05 //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) {
|
||||
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();
|
||||
} else if ((keys[32] || game.mouseDownRight) && mech.fieldCDcycle < mech.cycle) { //not hold but field button is pressed
|
||||
const DRAIN = 0.0006
|
||||
if (mech.fieldMeter > DRAIN) {
|
||||
mech.fieldMeter -= DRAIN;
|
||||
|
||||
//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())) + ")";
|
||||
//calculate laser collision
|
||||
let best;
|
||||
let range = 80 + (mech.crouch ? 500 : 300) * Math.sqrt(Math.random()) //+ 100 * Math.sin(mech.cycle * 0.3);
|
||||
const dir = mech.angle // + 0.04 * (Math.random() - 0.5)
|
||||
const path = [{
|
||||
x: mech.pos.x + 20 * Math.cos(dir),
|
||||
y: mech.pos.y + 20 * Math.sin(dir)
|
||||
},
|
||||
{
|
||||
x: mech.pos.x + range * Math.cos(dir),
|
||||
y: mech.pos.y + range * Math.sin(dir)
|
||||
}
|
||||
];
|
||||
const vertexCollision = function (v1, v1End, domain) {
|
||||
for (let i = 0; i < domain.length; ++i) {
|
||||
let vertices = domain[i].vertices;
|
||||
const len = vertices.length - 1;
|
||||
for (let j = 0; j < len; j++) {
|
||||
results = game.checkLineIntersection(v1, v1End, vertices[j], vertices[j + 1]);
|
||||
if (results.onLine1 && results.onLine2) {
|
||||
const dx = v1.x - results.x;
|
||||
const dy = v1.y - results.y;
|
||||
const dist2 = dx * dx + dy * dy;
|
||||
if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) {
|
||||
best = {
|
||||
x: results.x,
|
||||
y: results.y,
|
||||
dist2: dist2,
|
||||
who: domain[i],
|
||||
v1: vertices[j],
|
||||
v2: vertices[j + 1]
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
results = game.checkLineIntersection(v1, v1End, vertices[0], vertices[len]);
|
||||
if (results.onLine1 && results.onLine2) {
|
||||
const dx = v1.x - results.x;
|
||||
const dy = v1.y - results.y;
|
||||
const dist2 = dx * dx + dy * dy;
|
||||
if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) {
|
||||
best = {
|
||||
x: results.x,
|
||||
y: results.y,
|
||||
dist2: dist2,
|
||||
who: domain[i],
|
||||
v1: vertices[0],
|
||||
v2: vertices[len]
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//check for collisions
|
||||
best = {
|
||||
x: null,
|
||||
y: null,
|
||||
dist2: Infinity,
|
||||
who: null,
|
||||
v1: null,
|
||||
v2: null
|
||||
};
|
||||
vertexCollision(path[0], path[1], mob);
|
||||
vertexCollision(path[0], path[1], map);
|
||||
vertexCollision(path[0], path[1], body);
|
||||
if (best.dist2 != Infinity) { //if hitting something
|
||||
path[path.length - 1] = {
|
||||
x: best.x,
|
||||
y: best.y
|
||||
};
|
||||
if (best.who.alive) {
|
||||
const dmg = 0.35 * b.dmgScale; //********** SCALE DAMAGE HERE *********************
|
||||
best.who.damage(dmg);
|
||||
best.who.locatePlayer();
|
||||
|
||||
//push mobs away
|
||||
const force = Matter.Vector.mult(Matter.Vector.normalise(Matter.Vector.sub(mech.pos, path[1])), -0.01 * Math.sqrt(best.who.mass))
|
||||
Matter.Body.applyForce(best.who, path[1], force)
|
||||
// const angle = Math.atan2(player.position.y - best.who.position.y, player.position.x - best.who.position.x);
|
||||
// const mass = Math.min(Math.sqrt(best.who.mass), 6);
|
||||
// Matter.Body.setVelocity(best.who, {
|
||||
// x: best.who.velocity.x * 0.85 - 3 * Math.cos(angle) / mass,
|
||||
// y: best.who.velocity.y * 0.85 - 3 * Math.sin(angle) / mass
|
||||
// });
|
||||
|
||||
//draw mob damage circle
|
||||
game.drawList.push({
|
||||
x: path[1].x,
|
||||
y: path[1].y,
|
||||
radius: Math.sqrt(dmg) * 50,
|
||||
color: "rgba(255,0,255,0.2)",
|
||||
time: game.drawTime * 4
|
||||
});
|
||||
} else if (!best.who.isStatic) {
|
||||
//push blocks away
|
||||
const force = Matter.Vector.mult(Matter.Vector.normalise(Matter.Vector.sub(mech.pos, path[1])), -0.006 * Math.sqrt(Math.sqrt(best.who.mass)))
|
||||
Matter.Body.applyForce(best.who, path[1], force)
|
||||
}
|
||||
}
|
||||
|
||||
//draw blowtorch laser beam
|
||||
ctx.strokeStyle = "rgba(255,0,255,0.1)"
|
||||
ctx.lineWidth = 14
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(path[0].x, path[0].y);
|
||||
ctx.lineTo(path[1].x, path[1].y);
|
||||
ctx.stroke();
|
||||
ctx.strokeStyle = "#f0f";
|
||||
ctx.lineWidth = 2
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(path[0].x, path[0].y);
|
||||
ctx.lineTo(path[1].x, path[1].y);
|
||||
ctx.stroke();
|
||||
|
||||
//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);
|
||||
const step = range / 10
|
||||
for (let i = 0; i < 8; i++) {
|
||||
x += step * (Dx + 1.5 * (Math.random() - 0.5))
|
||||
y += step * (Dy + 1.5 * (Math.random() - 0.5))
|
||||
ctx.lineTo(x, y);
|
||||
}
|
||||
ctx.lineWidth = 2 * Math.random();
|
||||
ctx.stroke();
|
||||
|
||||
mech.pushMobs360(100);
|
||||
mech.grabPowerUp();
|
||||
mech.lookForPickUp();
|
||||
} else {
|
||||
ctx.fillStyle = "rgba(255,50,150," + (0.02 + mech.fieldMeter * (0.18 + 0.18 * Math.random())) + ")";
|
||||
mech.fieldCDcycle = mech.cycle + 120; //if out of energy
|
||||
}
|
||||
// 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 {
|
||||
@@ -1460,6 +1554,79 @@ 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);
|
||||
|
||||
Reference in New Issue
Block a user