planetesimals broadcast

tech: inductive coupling - regen is increased by 500%, but you only regen when crouched

tech gun turret gives 55% -> 60% harm reduction
  also I fixed a bug where it was giving 45% not 55%

old tech inductive coupling is renamed: permittivity
permittivity gives 3 -> 4 max energy per unused power up
1st ionization energy gives 6 -> 7 max energy per heal

tech expansion - no longer costs energy to expand standing wave field

JUNK tech planetesimals now can spawn tech in n-gon
  or kill the player in n-gon
This commit is contained in:
landgreen
2021-11-06 07:26:14 -07:00
parent b5738e2480
commit d77dde462e
9 changed files with 128 additions and 867 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@@ -1115,7 +1115,7 @@ const b = {
const cycles = 80 const cycles = 80
const speed = input.down ? 35 : 20 //input.down ? 43 : 32 const speed = input.down ? 35 : 20 //input.down ? 43 : 32
const g = input.down ? 0.137 : 0.135 const g = input.down ? 0.137 : 0.135
const v = { x: m.Vx / 2 + speed * Math.cos(m.angle), y: m.Vy / 2 + speed * Math.sin(m.angle) } const v = { x: speed * Math.cos(m.angle), y: speed * Math.sin(m.angle) }
ctx.strokeStyle = "rgba(68, 68, 68, 0.2)" //color.map ctx.strokeStyle = "rgba(68, 68, 68, 0.2)" //color.map
ctx.lineWidth = 2 ctx.lineWidth = 2
ctx.beginPath() ctx.beginPath()
@@ -1138,7 +1138,7 @@ const b = {
if (gunIndex) b.guns[gunIndex].do = function() { if (gunIndex) b.guns[gunIndex].do = function() {
const cycles = Math.floor(input.down ? 50 : 30) //30 const cycles = Math.floor(input.down ? 50 : 30) //30
const speed = input.down ? 44 : 35 const speed = input.down ? 44 : 35
const v = { x: m.Vx / 2 + speed * Math.cos(m.angle), y: m.Vy / 2 + speed * Math.sin(m.angle) } const v = { x: speed * Math.cos(m.angle), y: speed * Math.sin(m.angle) }
ctx.strokeStyle = "rgba(68, 68, 68, 0.2)" //color.map ctx.strokeStyle = "rgba(68, 68, 68, 0.2)" //color.map
ctx.lineWidth = 2 ctx.lineWidth = 2
ctx.beginPath() ctx.beginPath()
@@ -1153,7 +1153,7 @@ const b = {
if (gunIndex) b.guns[gunIndex].do = function() { if (gunIndex) b.guns[gunIndex].do = function() {
const cycles = Math.floor(input.down ? 120 : 80) //30 const cycles = Math.floor(input.down ? 120 : 80) //30
const speed = input.down ? 43 : 32 const speed = input.down ? 43 : 32
const v = { x: m.Vx / 2 + speed * Math.cos(m.angle), y: m.Vy / 2 + speed * Math.sin(m.angle) } const v = { x: speed * Math.cos(m.angle), y: speed * Math.sin(m.angle) } //m.Vy / 2 + removed to make the path less jerky
ctx.strokeStyle = "rgba(68, 68, 68, 0.2)" //color.map ctx.strokeStyle = "rgba(68, 68, 68, 0.2)" //color.map
ctx.lineWidth = 2 ctx.lineWidth = 2
ctx.beginPath() ctx.beginPath()
@@ -3457,10 +3457,13 @@ const b = {
this.lastLookCycle = simulation.cycle + (this.isUpgraded ? 21 : 110) this.lastLookCycle = simulation.cycle + (this.isUpgraded ? 21 : 110)
for (let i = 0, len = mob.length; i < len; i++) { for (let i = 0, len = mob.length; i < len; i++) {
const dist = Vector.magnitudeSquared(Vector.sub(this.position, mob[i].position)); const dist = Vector.magnitudeSquared(Vector.sub(this.position, mob[i].position));
if (dist < 3000000 && //1400*1400 if (
!mob[i].isBadTarget &&
dist < 3000000 &&
Matter.Query.ray(map, this.position, mob[i].position).length === 0 && Matter.Query.ray(map, this.position, mob[i].position).length === 0 &&
Matter.Query.ray(body, this.position, mob[i].position).length === 0 && Matter.Query.ray(body, this.position, mob[i].position).length === 0 &&
!mob[i].isShielded) { !mob[i].isShielded
) {
const SPEED = 35 const SPEED = 35
const unit = Vector.normalise(Vector.sub(Vector.add(mob[i].position, Vector.mult(mob[i].velocity, Math.sqrt(dist) / 60)), this.position)) const unit = Vector.normalise(Vector.sub(Vector.add(mob[i].position, Vector.mult(mob[i].velocity, Math.sqrt(dist) / 60)), this.position))
b.nail(this.position, Vector.mult(unit, SPEED)) b.nail(this.position, Vector.mult(unit, SPEED))

View File

@@ -660,6 +660,7 @@ document.getElementById("experiment-button").addEventListener("click", () => { /
openExperimentMenu(); openExperimentMenu();
}); });
// ************************************************************************************************ // ************************************************************************************************
// inputs // inputs
// ************************************************************************************************ // ************************************************************************************************

View File

@@ -15,10 +15,10 @@ const level = {
// localSettings.levelsClearedLastGame = 10 // localSettings.levelsClearedLastGame = 10
// level.difficultyIncrease(30) //30 is near max on hard //60 is near max on why // level.difficultyIncrease(30) //30 is near max on hard //60 is near max on why
// simulation.isHorizontalFlipped = true // simulation.isHorizontalFlipped = true
// m.setField("time dilation") // m.setField("metamaterial cloaking")
// b.giveGuns("grenades") b.giveGuns("laser")
// tech.giveTech("neutron bomb") // tech.giveTech("spherical harmonics")
// tech.giveTech("vacuum bomb") tech.giveTech("relative permittivity")
// tech.giveTech("causality bombs") // tech.giveTech("causality bombs")
// for (let i = 0; i < 2; i++) tech.giveTech("refractory metal") // for (let i = 0; i < 2; i++) tech.giveTech("refractory metal")
// tech.giveTech("antiscience") // tech.giveTech("antiscience")
@@ -26,6 +26,11 @@ const level = {
// for (let i = 0; i < 2; i++) tech.giveTech("laser-bot") // for (let i = 0; i < 2; i++) tech.giveTech("laser-bot")
// tech.isCancelDuplication = true // tech.isCancelDuplication = true
level.intro(); //starting level level.intro(); //starting level
// level.testing(); //not in rotation, used for testing // level.testing(); //not in rotation, used for testing
// level.template(); //not in rotation, blank start new map development // level.template(); //not in rotation, blank start new map development
@@ -94,7 +99,7 @@ const level = {
} }
} }
if (tech.isExtraMaxEnergy) { if (tech.isExtraMaxEnergy) {
tech.healMaxEnergyBonus += 0.03 * powerUps.totalPowerUps //Math.min(0.02 * powerUps.totalPowerUps, 0.51) tech.healMaxEnergyBonus += 0.04 * powerUps.totalPowerUps //Math.min(0.02 * powerUps.totalPowerUps, 0.51)
m.setMaxEnergy(); m.setMaxEnergy();
} }
if (tech.isGunCycle) { if (tech.isGunCycle) {

View File

@@ -1,807 +0,0 @@
/* http://brm.io/matter-js/docs/
http://brm.io/matter-js/demo/#mixed
https://github.com/liabru/matter-js/blob/master/demo/js/Demo.js
git hub gist:
https://gist.github.com/lilgreenland/8f2a2c033fdf3d5546a0ca5d73a2ae11
todo:
can you render bullets a different color? // red?
maybe add the ability to put up shields to survive collisions?
maybe add durability regeneration
fix new mass spawn so that it will pick a new location if the first spawn location already has a mass
*/
function planetesimals() {
//pause n-gon
// if (!simulation.isChoosing && input.isPauseKeyReady && m.alive) {
// input.isPauseKeyReady = false
// setTimeout(function() {
// input.isPauseKeyReady = true
// }, 300);
// if (simulation.paused) {
// build.unPauseGrid()
// simulation.paused = false;
// // level.levelAnnounce();
// document.body.style.cursor = "none";
// requestAnimationFrame(cycle);
// } else {
// simulation.paused = true;
// build.pauseGrid()
// document.body.style.cursor = "auto";
// if (tech.isGunSwitchField || simulation.testing) {
// document.getElementById("pause-field").addEventListener("click", () => {
// const energy = m.energy
// m.setField((m.fieldMode === m.fieldUpgrades.length - 1) ? 1 : m.fieldMode + 1) //cycle to next field
// m.energy = energy
// document.getElementById("pause-field").innerHTML = `<div class="grid-title"><div class="circle-grid field"></div> &nbsp; ${m.fieldUpgrades[m.fieldMode].name}</div> ${m.fieldUpgrades[m.fieldMode].description}`
// });
// }
// }
// }
"use strict"; //strict mode to catch errors
//game objects values
var game = {
cycle: 0,
width: 0,
height: 0,
scale: 0.5,
gravity: 0.00011,
totalMass: 0,
massSize: 0,
level: 1,
startingMassValue: 0,
massSegment: 0,
clearThreshold: 0.2, // there must be less than this percent to move on to the next level
currentMass: 0,
explodeMin: 8000,
HUD: true,
};
function levelScaling() {
//game.gravity = 0.00011; // + 0.000012 * game.level;
game.width = 2000 * game.level; //shapes walls and spawn locations
game.height = 2000 * game.level; //shapes walls and spawn locations
game.scale = 1.2 / (Math.log(game.level + 1)); //0.6 + 1.0 / (game.level); //controls map zoom
game.totalMass = 3 + game.level * 1; //how many masses to spawn at start of level
game.massSize = 3 + game.level * 3; //adds the average length of a segment on a masses's vertices
game.massSegment = 0.1 + 0.1 / game.level;
}
//looks for key presses and logs them
var keys = [];
document.body.addEventListener("keydown", function(e) {
keys[e.keyCode] = true;
});
document.body.addEventListener("keyup", function(e) {
keys[e.keyCode] = false;
});
// module aliases
var Engine = Matter.Engine,
World = Matter.World,
Events = Matter.Events,
Composite = Matter.Composite,
Vertices = Matter.Vertices,
Body = Matter.Body,
Bodies = Matter.Bodies;
// create an engine
var engine = Engine.create();
//turn off gravity
engine.world.gravity.y = 0;
// run the engine
// Engine.run(engine);
Matter.Runner.run(engine)
function addWalls() {
//add the walls
var wallSettings = {
size: 200,
isStatic: true,
render: {
restitution: 0,
fillStyle: 'rgba(0, 0, 0, 0.0)',
strokeStyle: '#00ffff'
}
};
World.add(engine.world, [
Bodies.rectangle(game.width * 0.5, -wallSettings.size * 0.5, game.width, wallSettings.size, wallSettings), //top
Bodies.rectangle(game.width * 0.5, game.height + wallSettings.size * 0.5, game.width, wallSettings.size, wallSettings), //bottom
Bodies.rectangle(-wallSettings.size * 0.5, game.height * 0.5, wallSettings.size, game.height + wallSettings.size * 2, wallSettings), //left
Bodies.rectangle(game.width + wallSettings.size * 0.5, game.height * 0.5, wallSettings.size, game.height + wallSettings.size * 2, wallSettings) //right
]);
}
//add the masses
var mass = [];
function addPlayer() {
//add the player object as the first mass in the array
mass.push();
//var arrow = Vertices.fromPath('100 0 75 50 100 100 25 100 0 50 25 0');
var arrow = Vertices.fromPath('0 15 -10 -15 10 -15');
mass[0] = Matter.Bodies.fromVertices(Math.random() * game.width, Math.random() * game.height, arrow, {
//density: 0.001,
alive: true,
friction: 0,
frictionStatic: 0,
frictionAir: 0,
restitution: 0, //bounce 1 = 100% elastic
density: 0.003333,
thrust: 0.0004, //forward acceleration, if mass goes up this needs to go up
yaw: 0.00133, //angular acceleration, needs to be higher with larger mass
rotationLimit: 0.05, //max acceleration for player in radians/cycle
angularFriction: 0.98, // 1 = no friction, 0.9 = high friction
durability: 1,
fireCD: 0,
lastPlayerVelocity: { //for keeping track of damamge from too much acceleration
x: 0,
y: 0
},
});
World.add(engine.world, mass[0]);
}
function randomConvexPolygon(size) { //returns a string of vectors that make a convex polygon
var polyVector = '';
var x = 0;
var y = 0;
var r = 0;
var angle = 0;
for (var i = 1; i < 60; i++) {
angle += 0.1 + Math.random() * game.massSegment; //change in angle in radians
if (angle > 2 * Math.PI) {
break; //stop before it becomes convex
}
r = 2 + Math.random() * 2;
x = Math.round(x + r * Math.cos(angle));
y = Math.round(y + r * Math.sin(angle));
polyVector = polyVector.concat(x * size + ' ' + y * size + ' ');
}
return polyVector;
}
function addMassVector(x, y, Vx, Vy, size) {
var verticies = [];
var vector = Vertices.fromPath(randomConvexPolygon(size));
var i = mass.length;
mass.push();
mass[i] = Matter.Bodies.fromVertices(x, y, vector, { // x,y,vectors,{options}
friction: 0,
frictionStatic: 0,
frictionAir: 0,
restitution: 1,
angle: Math.random() * 2 * Math.PI
});
Matter.Body.setVelocity(mass[i], {
x: Vx,
y: Vy
});
Matter.Body.setAngularVelocity(mass[i], (Math.random() - 0.5) * 0.03);
World.add(engine.world, mass[i]);
}
function addMass(x, y, r, sides, Vx, Vy) {
var i = mass.length;
mass.push();
mass[i] = Bodies.polygon(x, y, sides, r, {
friction: 0,
frictionStatic: 0,
frictionAir: 0,
restitution: 1,
});
Matter.Body.setVelocity(mass[i], {
x: Vx,
y: Vy
});
Matter.Body.setAngularVelocity(mass[i], (Math.random() - 0.5) * 0.03);
World.add(engine.world, mass[i]);
}
function clearMasses() {
World.clear(engine.world, false);
console.log('clear')
mass = [];
}
function spawnSetup() {
//make the level indicator more clear on a new level
// document.getElementById("level").innerHTML = 'system ' + game.level;
// document.getElementById("level").style.color = 'white';
// document.getElementById("level").style.fontSize = '500%';
// document.getElementById("level").style.left = '40%';
// document.getElementById("level").style.position = 'absolute';
// setTimeout(levelFontSize, 3000);
//after 3 seconds return to normal style
// function levelFontSize(size) {
// document.getElementById("level").style.color = 'grey';
// document.getElementById("level").style.position = '';
// document.getElementById("level").style.left = '';
// document.getElementById("level").style.fontSize = '100%';
// }
levelScaling();
clearMasses();
addWalls();
addPlayer();
//add other masses
for (var j = 0; j < game.totalMass; j++) {
// addMassVector(x,y,Vx,Vy,size)
addMassVector(game.width * 0.2 + Math.random() * game.width * 0.6,
game.height * 0.2 + Math.random() * game.height * 0.6,
0, //(0.5 - Math.random()) * 4,
0,
Math.random() * 3 + game.massSize
);
}
//determine how much mass is in the game at the start
game.startingMassValue = 0;
for (var i = 0; i < mass.length; i++) {
game.startingMassValue += mass[i].mass;
}
game.currentMass = game.startingMassValue;
}
spawnSetup();
function repopulateMasses() {
game.currentMass = 0;
for (var i = 0; i < mass.length; i++) {
game.currentMass += mass[i].mass;
}
if (game.currentMass < game.startingMassValue * game.clearThreshold) {
game.level++;
spawnSetup();
mass[0].durability = 1;
}
}
var bullet = [];
function fireBullet() { //addMass(x, y, r, sides, Vx, Vy)
var i = bullet.length;
var angle = mass[0].angle + Math.PI * 0.5;
var speed = 9;
var playerDist = 25;
bullet.push();
bullet[i] = Bodies.polygon(
mass[0].position.x + playerDist * Math.cos(angle),
mass[0].position.y + playerDist * Math.sin(angle),
3, //sides
2, { //radius
angle: Math.random() * 6.28,
friction: 0,
frictionStatic: 0,
frictionAir: 0,
restitution: 1,
endCycle: game.cycle + 90, // life span for a bullet (60 per second)
});
Matter.Body.setVelocity(bullet[i], {
x: mass[0].velocity.x + speed * Math.cos(angle),
y: mass[0].velocity.y + speed * Math.sin(angle)
});
Matter.Body.setAngularVelocity(bullet[i], (Math.random() - 0.5) * 1);
World.add(engine.world, bullet[i]);
}
function bulletEndCycle() {
for (var i = 0; i < bullet.length; i++) {
if (bullet[i].endCycle < game.cycle) {
Matter.World.remove(engine.world, bullet[i]);
bullet.splice(i, 1);
}
}
}
function controls() {
if (mass[0].alive) {
if (keys[32] && mass[0].fireCD < game.cycle) {
mass[0].fireCD = game.cycle + 10; // ?/60 seconds of cooldown before you can fire
fireBullet();
}
if (keys[38] || keys[87]) { //forward thrust
mass[0].force.x += mass[0].thrust * Math.cos(mass[0].angle + Math.PI * 0.5);
mass[0].force.y += mass[0].thrust * Math.sin(mass[0].angle + Math.PI * 0.5);
thrustGraphic();
} else if (keys[40] || keys[83]) { //reverse thrust
mass[0].force = {
x: -mass[0].thrust * 0.5 * Math.cos(mass[0].angle + Math.PI * 0.5),
y: -mass[0].thrust * 0.5 * Math.sin(mass[0].angle + Math.PI * 0.5)
};
torqueGraphic(-1);
torqueGraphic(1);
}
//rotate left and right
if ((keys[37] || keys[65])) { //&& mass[0].angularVelocity > -mass[0].rotationLimit) {
mass[0].torque = -mass[0].yaw; //counter clockwise
torqueGraphic(-1);
} else if ((keys[39] || keys[68])) { //&& mass[0].angularVelocity < mass[0].rotationLimit) {
mass[0].torque = mass[0].yaw; //clockwise
torqueGraphic(1);
}
//angular friction if spinning too fast
if (Math.abs(mass[0].angularVelocity) > mass[0].rotationLimit) {
Matter.Body.setAngularVelocity(mass[0], mass[0].angularVelocity * mass[0].angularFriction);
}
}
}
function torqueGraphic(dir) { //thrust graphic when holding rotation keys
ctx.save();
//ctx.translate(0.5 * canvas.width, 0.5 * canvas.height)
ctx.rotate(mass[0].angle - Math.PI * 0.6 * dir);
ctx.translate(0, -23);
var grd = ctx.createLinearGradient(0, 0, 0, 15);
grd.addColorStop(0.1, 'rgba(0, 0, 0, 0)');
grd.addColorStop(1, 'rgba(160, 192, 255, 1)');
ctx.fillStyle = grd;
ctx.beginPath();
ctx.moveTo(dir * 6 * (Math.random() - 0.5) + 12 * dir, 6 * (Math.random() - 0.5));
ctx.lineTo(dir * 8, 14);
ctx.lineTo(dir * 12, 14);
ctx.fill();
ctx.restore();
}
function thrustGraphic() {
//ctx.fillStyle= "#90b0ff";
ctx.save();
//ctx.translate(0.5 * canvas.width, 0.5 * canvas.height)
ctx.rotate(mass[0].angle);
ctx.translate(0, -33);
var grd = ctx.createLinearGradient(0, 0, 0, 15);
grd.addColorStop(0, 'rgba(0, 0, 0, 0)');
grd.addColorStop(1, 'rgba(160, 192, 255, 1)');
ctx.fillStyle = grd;
ctx.beginPath();
ctx.moveTo(10 * (Math.random() - 0.5), 10 * (Math.random() - 0.5));
ctx.lineTo(7, 20);
ctx.lineTo(-7, 20);
ctx.fill();
ctx.restore();
}
function gravity() {
var length = mass.length;
var Dx = 0;
var Dy = 0;
var force = 0;
var angle = 0;
var i = 0;
var j = 0;
//gravity for array masses, but not player: mass[0]
for (i = 0; i < length; i++) {
for (j = 0; j < length; j++) {
if (i != j) {
Dx = mass[j].position.x - mass[i].position.x;
Dy = mass[j].position.y - mass[i].position.y;
force = game.gravity * mass[j].mass * mass[i].mass / (Math.sqrt(Dx * Dx + Dy * Dy));
angle = Math.atan2(Dy, Dx);
mass[i].force.x += force * Math.cos(angle);
mass[i].force.y += force * Math.sin(angle);
}
}
}
//gravity for bullets
var Blength = bullet.length;
for (i = 0; i < Blength; i++) {
for (j = 0; j < length; j++) { //bullets only feel gravity, they don't create it
Dx = mass[j].position.x - bullet[i].position.x;
Dy = mass[j].position.y - bullet[i].position.y;
force = game.gravity * mass[j].mass * bullet[i].mass / (Math.sqrt(Dx * Dx + Dy * Dy));
angle = Math.atan2(Dy, Dx);
bullet[i].force.x += force * Math.cos(angle);
bullet[i].force.y += force * Math.sin(angle);
}
}
}
function damage() { //changes player health if velocity changes too much
var limit2 = 9; //square of velocity damamge limit
var dX = Math.abs(mass[0].lastPlayerVelocity.x - mass[0].velocity.x);
var dY = Math.abs(mass[0].lastPlayerVelocity.y - mass[0].velocity.y);
var dV2 = dX * dX + dY * dY; //we are skipping the square root
if (dV2 > limit2) { //did velocity change enough to take damage
mass[0].durability -= Math.sqrt(dV2 - limit2) * 0.02; //player takes damage
if (mass[0].durability < 0 && mass[0].alive) { //player dead?
mass[0].alive = false;
//spawn player explosion debris
for (var j = 0; j < 10; j++) { //addMass(x, y, r, sides, Vx, Vy)
addMass(mass[0].position.x + 10 * (0.5 - Math.random()),
mass[0].position.y + 10 * (0.5 - Math.random()),
5,
3,
(0.5 - Math.random()) * 8 + mass[0].velocity.x,
(0.5 - Math.random()) * 8 + mass[0].velocity.y);
}
//shrink player to match debris size
Matter.Body.scale(mass[0], 0.4, 0.4);
//reset masses after a few seconds
window.setTimeout(spawnSetup, 6000);
}
}
//keep track of last player velocity to calculate changes in velocity
mass[0].lastPlayerVelocity.x = mass[0].velocity.x;
mass[0].lastPlayerVelocity.y = mass[0].velocity.y;
}
//bullet collision event
Events.on(engine, 'collisionStart', function(event) {
//slice the polygon up into sections
function slicePoly(m, start, end) { //cut a mass into two sectons
//build new string vector array that matches some of the reference mass
var polyVector = '';
for (var i = start; i < end; i++) {
polyVector = polyVector.concat(mass[m].vertices[i].x + ' ' + mass[m].vertices[i].y + ' ');
}
//buggy: making polygons noncolide. not sure why
//if (end = mass[m].vertices.length) { //catch the first vertices if the polygon hits the last
// polyVector = polyVector.concat(mass[m].vertices[0].x + ' ' + mass[m].vertices[0].y + ' '); }
var verticies = []; //build the polygon in matter.js
var vector = Vertices.fromPath(polyVector);
//add string vector array to game as a polygon
var len = mass.length;
mass.push();
mass[len] = Matter.Bodies.fromVertices(0, 0, vector, { // x,y,vectors,{options}
friction: 0,
frictionStatic: 0,
frictionAir: 0,
restitution: 1
});
World.add(engine.world, mass[len]);
//scale down the polygon a bit to help with collisions
Matter.Body.scale(mass[len], 0.9, 0.9);
//move polygon into position
var vectorPos = Matter.Vertices.centre(vector); //find the center of new polygon
Matter.Body.translate(mass[len], {
x: vectorPos.x,
y: vectorPos.y
});
//give a velocity pointed away from the old mass's center so it explodes
var angle = Math.atan2(mass[len].position.y - mass[m].position.y, mass[len].position.x - mass[m].position.x);
Matter.Body.setVelocity(mass[len], {
x: mass[m].velocity.x + 2 * Math.cos(angle),
y: mass[m].velocity.y + 2 * Math.sin(angle)
});
//add some spin
Matter.Body.setAngularVelocity(mass[len], (Math.random() - 0.5) * 0.1);
}
function hit(i, b, m) {
//match the collisions pair id to the mass
for (var j = 1; j < mass.length; j++) { //start at 1 to skip the player
if (mass[j].id === m.id) {
//remove bullet
Matter.World.remove(engine.world, bullet[i]);
bullet.splice(i, 1);
// explosion graphics
var driftSpeed = 1;
var length = mass[j].vertices.length - 1;
var dx = (mass[j].vertices[length].x - mass[j].position.x);
var dy = (mass[j].vertices[length].y - mass[j].position.y);
var r = Math.sqrt(dx * dx + dy * dy) * 1.5; // *1.5 give the explosion outward spread
var angle = Math.atan2(dy, dx);
boom.push({ //the line form the 1st and last vertex
x1: mass[j].vertices[length].x,
y1: mass[j].vertices[length].y,
x2: mass[j].vertices[0].x,
y2: mass[j].vertices[0].y,
alpha: 1,
driftVx: mass[j].velocity.x + (Math.random() - 0.5) * driftSpeed + r * mass[j].angularSpeed * Math.cos(angle),
driftVy: mass[j].velocity.y + (Math.random() - 0.5) * driftSpeed + r * mass[j].angularSpeed * Math.sin(angle),
});
for (var n = 0; n < length; n++) {
dx = (mass[j].vertices[n].x - mass[j].position.x);
dy = (mass[j].vertices[n].y - mass[j].position.y);
r = Math.sqrt(dx * dx + dy * dy);
angle = Math.atan2(dy, dx);
boom.push({
x1: mass[j].vertices[n].x,
y1: mass[j].vertices[n].y,
x2: mass[j].vertices[n + 1].x,
y2: mass[j].vertices[n + 1].y,
alpha: 1,
driftVx: mass[j].velocity.x + (Math.random() - 0.5) * driftSpeed + r * mass[j].angularSpeed * Math.cos(angle),
driftVy: mass[j].velocity.y + (Math.random() - 0.5) * driftSpeed + r * mass[j].angularSpeed * Math.sin(angle),
});
}
//choose to slice
if (mass[j].vertices.length > 13) {
var cut = 6 + Math.floor(Math.random() * 4);
slicePoly(j, 0, cut);
//sliceChoices(mass.length - 1);
slicePoly(j, cut - 1, mass[j].vertices.length);
//sliceChoices(mass.length - 1);
Matter.World.remove(engine.world, mass[j]);
mass.splice(j, 1);
} else {
Matter.World.remove(engine.world, mass[j]);
mass.splice(j, 1);
}
return;
}
}
}
//check to see if one of the collisison pairs is a bullet
var pairs = event.pairs;
for (var i = 0, j = pairs.length; i != j; ++i) {
var pair = pairs[i];
for (var k = 0; k < bullet.length; k++) {
if (pair.bodyA === bullet[k]) {
hit(k, pair.bodyA, pair.bodyB);
repopulateMasses();
break;
} else if (pair.bodyB === bullet[k]) {
hit(k, pair.bodyB, pair.bodyA);
repopulateMasses();
break;
}
}
}
});
var boom = [];
function explosions() {
var i = boom.length;
ctx.lineWidth = 1.5;
while (i--) {
ctx.strokeStyle = 'rgba(255, 255, 255, ' + boom[i].alpha + ')';
//drift vector lines around
boom[i].x1 += boom[i].driftVx;
boom[i].y1 += boom[i].driftVy;
boom[i].x2 += boom[i].driftVx;
boom[i].y2 += boom[i].driftVy;
//draw vector lines
ctx.beginPath();
ctx.moveTo(boom[i].x1, boom[i].y1);
ctx.lineTo(boom[i].x2, boom[i].y2);
ctx.stroke();
//remove vector lines if they are too old
boom[i].alpha -= 0.03;
if (boom[i].alpha < 0.01) {
boom.splice(i, 1);
}
}
}
//set up render
var canvas = document.createElement('canvas'),
ctx = canvas.getContext('2d');
//make canvas fill window
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
document.body.appendChild(canvas);
window.onresize = function(event) {
ctx.canvas.width = window.innerWidth;
ctx.canvas.height = window.innerHeight;
starsMoveRandom();
};
(function cycle() { //render loop
game.cycle++;
//ctx.fillStyle = 'rgba(0, 0, 0, 0.2)'; //trails simulate a old arcade cathode look
//ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.clearRect(0, 0, canvas.width, canvas.height); //clear canvas for new cycle
bulletEndCycle();
damage();
gravity();
//background graphics
drawStars();
HUD();
ctx.save(); //move camera
ctx.translate(window.innerWidth * 0.5, window.innerHeight * 0.5);
ctx.scale(game.scale, game.scale);
controls();
ctx.translate(-mass[0].position.x, -mass[0].position.y);
//primary graphics
render();
drawVectors();
explosions();
ctx.restore(); //undo previous translation
//foreground graphics
miniMap();
completionBar();
durabilityBar();
window.requestAnimationFrame(cycle);
})();
function render() { //draw all the objects from matter.js physics engine
var bodies = Composite.allBodies(engine.world); //draw every object
//fill and stroke each body
ctx.lineWidth = 1.5;
ctx.strokeStyle = '#ffffff';
ctx.fillStyle = '#050505'; //'#111'; //'#0a0606';
ctx.beginPath();
for (var i = 0; i < bodies.length; i++) {
var vertices = bodies[i].vertices;
ctx.moveTo(vertices[0].x, vertices[0].y);
for (var j = 1; j < vertices.length; j++) {
ctx.lineTo(vertices[j].x, vertices[j].y);
}
ctx.lineTo(vertices[0].x, vertices[0].y);
}
ctx.fill();
ctx.stroke();
}
function drawVectors() { //render force and velocity vectors for each mass
if (game.HUD) {
var length = mass.length;
ctx.lineWidth = 1;
//velocity vector
//ctx.strokeStyle = 'rgba(0, 255, 255, 1)';
ctx.strokeStyle = '#00ffff';
ctx.beginPath();
for (var i = 0; i < length; i++) {
ctx.moveTo(mass[i].position.x, mass[i].position.y);
ctx.lineTo(mass[i].position.x + 10 * mass[i].velocity.x,
mass[i].position.y + 10 * mass[i].velocity.y);
}
ctx.stroke();
//force vector
//ctx.strokeStyle = 'rgba(255, 0, 255, 1)';
ctx.strokeStyle = '#ff00ff';
ctx.beginPath();
for (i = 0; i < length; i++) {
ctx.moveTo(mass[i].position.x, mass[i].position.y);
ctx.lineTo(mass[i].position.x + 600000 * mass[i].force.x / mass[i].mass,
mass[i].position.y + 600000 * mass[i].force.y / mass[i].mass);
}
ctx.stroke();
//angular motion vector
/* ctx.strokeStyle = 'rgba(255, 255, 00, 0.5)';//'#ff00ff';
ctx.beginPath();
if (mass[0].angularVelocity>0){
ctx.arc(mass[0].position.x,mass[0].position.y,20,Math.PI*0.5,53*mass[0].angularVelocity+Math.PI*0.5);
}else{
ctx.arc(mass[0].position.x,mass[0].position.y,20,53*mass[0].angularVelocity+Math.PI*0.5,Math.PI*0.5);
}
ctx.stroke(); */
}
}
function HUD() { //player data
// document.getElementById("level").innerHTML = 'system ' + game.level
if (game.HUD) { //testing and development data
document.getElementById("hud").innerHTML = '<table> ' +
//'<tr> <td>#:</td> <td>' + mass.length + '</td> </tr>' +
//'<tr> <td>level: </td> <td>' + game.level + '</td> </tr>' +
'<tr> <td>&nbsp;t:</td> <td>' + engine.timing.timestamp.toFixed(0) + '</td> </tr>' +
'<tr> <td style="color:#77f;">&nbsp;m:</td> <td>' + mass[0].mass.toFixed(2) + '</td> </tr>' +
'<tr> <td style="color:#77f;">&nbsp;θ:</td> <td>' + (Math.abs(mass[0].angle % (Math.PI * 2))).toFixed(2) + '</td> </tr>' +
'<tr> <td style="color:#77f;">dθ:</td> <td>' + mass[0].angularVelocity.toFixed(3) + '</td> </tr>' +
'<tr> <td style="color:#77f;">&nbsp;x:</td> <td>' + mass[0].position.x.toFixed(0) + '</td> </tr>' +
'<tr> <td style="color:#77f;">&nbsp;y:</td> <td>' + mass[0].position.y.toFixed(0) + '</td> </tr>' +
'<tr> <td style="color:#0dd;">Vx:</td> <td>' + mass[0].velocity.x.toFixed(2) + '</td> </tr>' +
'<tr> <td style="color:#0dd;">Vy:</td> <td>' + mass[0].velocity.y.toFixed(2) + '</td> </tr>' +
'<tr> <td style="color:#d0d;">Fx:</td> <td>' + mass[0].force.x.toFixed(6) + '</td> </tr>' +
'<tr> <td style="color:#d0d;">Fy:</td> <td>' + mass[0].force.y.toFixed(6) + '</td> </tr>' + '</table>';
} else {
document.getElementById("hud").innerHTML = "";
}
}
function durabilityBar() { // player health bar
var size = 200;
var x = 6;
var y = 6;
//ctx.lineWidth = 2;
//ctx.strokeStyle = '#999';
//ctx.strokeRect(x - 1, y - 1, size + 2, 12); //draw outline
//ctx.fillStyle = '#512';
ctx.fillStyle = 'rgba(255, 85, 119, 0.3)'
ctx.fillRect(x, y, size, 10); //draw bar
if (mass[0].alive) { //only draw bar if player is alive
ctx.fillStyle = 'rgba(255, 85, 119, 0.9)'
ctx.fillRect(x, y, size * mass[0].durability, 10); //draw bar
}
}
function completionBar() {
var size = 152;
var x = canvas.width - size - 4;
var y = 5;
//ctx.fillStyle = '#000007';
//ctx.fillRect(x, y, size, 5); //draw bar
ctx.fillStyle = 'rgba(85, 85, 170, 0.3)'
//ctx.fillStyle = '#55a';
ctx.fillRect(x, y, size, 5); //draw bar
//ctx.fillStyle = '#55a';
ctx.fillStyle = 'rgba(85, 85, 170, 0.9)'
ctx.fillRect(x, y, size * game.currentMass / game.startingMassValue, 5); //draw bar
//goal line
ctx.fillStyle = '#ffff00';
ctx.fillRect(x + size * game.clearThreshold, y, 1, 5); //draw bar
//outline of bar
//ctx.lineWidth = 1;
//ctx.strokeStyle = '#88f';
//ctx.strokeRect(x, y, size, 5); //draw outline
}
function miniMap() {
ctx.lineWidth = 1;
ctx.strokeStyle = '#88f';
ctx.beginPath();
var xOff = canvas.width - 5;
var yOff = 10;
var size = 150;
var scale = size / game.width;
ctx.fillStyle = 'rgba(0, 0, 50, 0.5)'
ctx.rect(xOff, yOff, -size, size);
ctx.stroke();
ctx.fill();
//draw dot for masses
ctx.fillStyle = '#aaf';
for (var i = 1; i < mass.length; i++) {
ctx.fillRect(mass[i].position.x * scale + xOff - size, mass[i].position.y * scale + yOff, 3, 3);
}
//draw player's dot
ctx.fillStyle = '#ffff00';
ctx.fillRect(mass[0].position.x * scale + xOff - size, mass[0].position.y * scale + yOff, 5, 5);
}
var star = [];
var totalStars = 100;
for (var i = 0; i < totalStars; i++) {
star.push({
x: Math.random() * window.innerWidth,
y: Math.random() * window.innerHeight
});
}
function starsMoveRandom() {
for (var i = 0; i < totalStars; i++) {
star[i].x = Math.random() * window.innerWidth;
star[i].y = Math.random() * window.innerHeight;
}
}
function drawStars() {
ctx.fillStyle = '#ffffff'; //'darkgrey'; //'rgba(255, 255, 255, 0.5)'
var parallax = 1;
var Vx = mass[0].velocity.x * game.scale;
var Vy = mass[0].velocity.y * game.scale;
var width = window.innerWidth;
var height = window.innerHeight;
for (var i = 0; i < totalStars; i++) {
star[i].x -= Vx;
star[i].y -= Vy;
ctx.fillRect(star[i].x, star[i].y, 1, 1);
if (star[i].x < 0) {
star[i].x = width;
star[i].y = Math.random() * height;
}
if (star[i].x > width) {
star[i].x = 0;
star[i].y = Math.random() * height;
}
if (star[i].y < 0) {
star[i].y = height;
star[i].x = Math.random() * width;
}
if (star[i].y > height) {
star[i].y = 0;
star[i].x = Math.random() * width;
}
}
}
}

View File

@@ -514,7 +514,7 @@ const m = {
if (tech.isHarmArmor && m.lastHarmCycle + 600 > m.cycle) dmg *= 0.33; if (tech.isHarmArmor && m.lastHarmCycle + 600 > m.cycle) dmg *= 0.33;
if (tech.isNoFireDefense && m.cycle > m.fireCDcycle + 120) dmg *= 0.3 if (tech.isNoFireDefense && m.cycle > m.fireCDcycle + 120) dmg *= 0.3
if (tech.energyRegen === 0) dmg *= 0.34 if (tech.energyRegen === 0) dmg *= 0.34
if (tech.isTurret && m.crouch) dmg *= 0.55; if (tech.isTurret && m.crouch) dmg *= 0.4;
if (tech.isEntanglement && b.inventory[0] === b.activeGun) { if (tech.isEntanglement && b.inventory[0] === b.activeGun) {
for (let i = 0, len = b.inventory.length; i < len; i++) dmg *= 0.87 // 1 - 0.15 for (let i = 0, len = b.inventory.length; i < len; i++) dmg *= 0.87 // 1 - 0.15
} }
@@ -1002,8 +1002,7 @@ const m = {
fieldMeterColor: "#0cf", fieldMeterColor: "#0cf",
drawFieldMeter(bgColor = "rgba(0, 0, 0, 0.4)", range = 60) { drawFieldMeter(bgColor = "rgba(0, 0, 0, 0.4)", range = 60) {
if (m.energy < m.maxEnergy) { if (m.energy < m.maxEnergy) {
if (m.immuneCycle < m.cycle) m.energy += m.fieldRegen; m.regenEnergy();
if (m.energy < 0) m.energy = 0
ctx.fillStyle = bgColor; ctx.fillStyle = bgColor;
const xOff = m.pos.x - m.radius * m.maxEnergy const xOff = m.pos.x - m.radius * m.maxEnergy
const yOff = m.pos.y - 50 const yOff = m.pos.y - 50
@@ -1018,9 +1017,30 @@ const m = {
ctx.fillStyle = m.fieldMeterColor; ctx.fillStyle = m.fieldMeterColor;
ctx.fillRect(xOff, yOff, range * m.energy, 10); ctx.fillRect(xOff, yOff, range * m.energy, 10);
} }
// else { },
// m.energy = m.maxEnergy drawFieldMeterCloaking: function() {
// } if (m.energy < m.maxEnergy) { // replaces m.drawFieldMeter() with custom code
m.regenEnergy();
const xOff = m.pos.x - m.radius * m.maxEnergy
const yOff = m.pos.y - 50
ctx.fillStyle = "rgba(0, 0, 0, 0.3)" //
ctx.fillRect(xOff, yOff, 60 * m.maxEnergy, 10);
ctx.fillStyle = "#fff" //m.cycle > m.lastKillCycle + 300 ? "#000" : "#fff" //"#fff";
ctx.fillRect(xOff, yOff, 60 * m.energy, 10);
ctx.beginPath()
ctx.rect(xOff, yOff, 60 * m.maxEnergy, 10);
ctx.strokeStyle = m.fieldMeterColor;
ctx.lineWidth = 1;
ctx.stroke();
}
},
regenEnergy: function() { //used in drawFieldMeter // rewritten by some tech
if (m.immuneCycle < m.cycle) m.energy += m.fieldRegen;
if (m.energy < 0) m.energy = 0
},
regenEnergyDefault: function() {
if (m.immuneCycle < m.cycle) m.energy += m.fieldRegen;
if (m.energy < 0) m.energy = 0
}, },
lookingAt(who) { lookingAt(who) {
//calculate a vector from body to player and make it length 1 //calculate a vector from body to player and make it length 1
@@ -1301,7 +1321,7 @@ const m = {
if (m.energy < 0) m.energy = 0; if (m.energy < 0) m.energy = 0;
m.fieldCDcycle = m.cycle + m.fieldBlockCD; m.fieldCDcycle = m.cycle + m.fieldBlockCD;
if (tech.blockingIce) { if (tech.blockingIce) {
for (let i = 0; i < fieldBlockCost * 50 * tech.blockingIce; i++) b.iceIX(3, 2 * Math.PI * Math.random(), m.pos) for (let i = 0; i < fieldBlockCost * 60 * tech.blockingIce; i++) b.iceIX(3, 2 * Math.PI * Math.random(), m.pos)
} }
const unit = Vector.normalise(Vector.sub(player.position, who.position)) const unit = Vector.normalise(Vector.sub(player.position, who.position))
if (tech.blockDmg) { if (tech.blockDmg) {
@@ -1536,12 +1556,12 @@ const m = {
} }
m.harmonicRadius = 1 //for smoothing function when player holds mouse (for harmonicAtomic) m.harmonicRadius = 1 //for smoothing function when player holds mouse (for harmonicAtomic)
m.harmonicAtomic = () => { //several ellipses spinning about different axises m.harmonicAtomic = () => { //several ellipses spinning about different axises
const rotation = simulation.cycle * 0.002 const rotation = simulation.cycle * 0.0031
const phase = simulation.cycle * 0.03 const phase = simulation.cycle * 0.023
const radius = m.fieldRange * m.harmonicRadius const radius = m.fieldRange * m.harmonicRadius
ctx.lineWidth = 1; ctx.lineWidth = 1;
ctx.strokeStyle = "rgba(110,170,200,0.9)" ctx.strokeStyle = "rgba(110,170,200,0.8)"
ctx.fillStyle = "rgba(110,170,200," + Math.min(0.7, m.energy * (0.13 + 0.15 * Math.random()) * (3 / tech.harmonics)) + ")"; ctx.fillStyle = "rgba(110,170,200," + Math.min(0.7, m.energy * (0.13 + 0.1 * Math.random()) * (3 / tech.harmonics)) + ")";
// ctx.fillStyle = "rgba(110,170,200," + Math.min(0.7, m.energy * (0.22 - 0.01 * tech.harmonics) * (0.5 + 0.5 * Math.random())) + ")"; // ctx.fillStyle = "rgba(110,170,200," + Math.min(0.7, m.energy * (0.22 - 0.01 * tech.harmonics) * (0.5 + 0.5 * Math.random())) + ")";
for (let i = 0; i < tech.harmonics; i++) { for (let i = 0; i < tech.harmonics; i++) {
ctx.beginPath(); ctx.beginPath();
@@ -1584,9 +1604,9 @@ const m = {
if (m.energy > 0.1 && m.fieldCDcycle < m.cycle) { if (m.energy > 0.1 && m.fieldCDcycle < m.cycle) {
if (tech.isStandingWaveExpand) { if (tech.isStandingWaveExpand) {
if (input.field) { if (input.field) {
const oldHarmonicRadius = m.harmonicRadius // const oldHarmonicRadius = m.harmonicRadius
m.harmonicRadius = 0.985 * m.harmonicRadius + 0.015 * 2.5 m.harmonicRadius = 0.985 * m.harmonicRadius + 0.015 * 2.5
m.energy -= 0.1 * (m.harmonicRadius - oldHarmonicRadius) // m.energy -= 0.1 * (m.harmonicRadius - oldHarmonicRadius)
} else { } else {
m.harmonicRadius = 0.995 * m.harmonicRadius + 0.005 m.harmonicRadius = 0.995 * m.harmonicRadius + 0.005
} }
@@ -2494,21 +2514,7 @@ const m = {
} }
} }
if (m.energy < m.maxEnergy) { // replaces m.drawFieldMeter() with custom code this.drawFieldMeterCloaking()
if (m.immuneCycle < m.cycle) m.energy += m.fieldRegen;
if (m.energy < 0) m.energy = 0
const xOff = m.pos.x - m.radius * m.maxEnergy
const yOff = m.pos.y - 50
ctx.fillStyle = "rgba(0, 0, 0, 0.3)" //
ctx.fillRect(xOff, yOff, 60 * m.maxEnergy, 10);
ctx.fillStyle = "#fff" //m.cycle > m.lastKillCycle + 300 ? "#000" : "#fff" //"#fff";
ctx.fillRect(xOff, yOff, 60 * m.energy, 10);
ctx.beginPath()
ctx.rect(xOff, yOff, 60 * m.maxEnergy, 10);
ctx.strokeStyle = m.fieldMeterColor;
ctx.lineWidth = 1;
ctx.stroke();
}
//show sneak attack status //show sneak attack status
if (m.cycle > m.lastKillCycle + 240) { if (m.cycle > m.lastKillCycle + 240) {

View File

@@ -443,7 +443,7 @@ const powerUps = {
} }
if (tech.healGiveMaxEnergy) { if (tech.healGiveMaxEnergy) {
tech.healMaxEnergyBonus += 0.06 tech.healMaxEnergyBonus += 0.07
m.setMaxEnergy(); m.setMaxEnergy();
} }
}, },

View File

@@ -556,19 +556,18 @@
this.refundAmount = 0 this.refundAmount = 0
} }
} }
}, },
{ {
name: "gun turret", name: "gun turret",
description: "reduce <strong class='color-harm'>harm</strong> by <strong>55%</strong> when <strong>crouching</strong>", description: "reduce <strong class='color-harm'>harm</strong> by <strong>60%</strong> when <strong>crouching</strong>",
maxCount: 1, maxCount: 1,
count: 0, count: 0,
frequency: 3, frequency: 3,
frequencyDefault: 3, frequencyDefault: 3,
allowed() { allowed() {
return tech.isCrouchAmmo && !tech.isEnergyHealth return (tech.isCrouchAmmo && !tech.isEnergyHealth) || tech.isCrouchRegen
}, },
requires: "desublimated ammunition, not mass-energy", requires: "relative permittivity, desublimated ammunition, not mass-energy",
effect() { effect() {
tech.isTurret = true tech.isTurret = true
}, },
@@ -2332,7 +2331,7 @@
{ {
name: "1st ionization energy", name: "1st ionization energy",
link: `<a target="_blank" href='https://en.wikipedia.org/wiki/Ionization_energy' class="link">1st ionization energy</a>`, link: `<a target="_blank" href='https://en.wikipedia.org/wiki/Ionization_energy' class="link">1st ionization energy</a>`,
description: `each ${powerUps.orb.heal()} you collect<br>increases your <strong>maximum</strong> <strong class='color-f'>energy</strong> by <strong>6</strong>`, description: `each ${powerUps.orb.heal()} you collect<br>increases your <strong>maximum</strong> <strong class='color-f'>energy</strong> by <strong>7</strong>`,
maxCount: 1, maxCount: 1,
count: 0, count: 0,
frequency: 2, frequency: 2,
@@ -2358,8 +2357,8 @@
} }
}, },
{ {
name: "inductive coupling", name: "permittivity",
description: "each unused <strong>power up</strong> at the end of a <strong>level</strong><br>adds 3 <strong>maximum</strong> <strong class='color-f'>energy</strong>", // <em>(up to 51 health per level)</em>", description: "each unused <strong>power up</strong> at the end of a <strong>level</strong><br>adds 4 <strong>maximum</strong> <strong class='color-f'>energy</strong>", // <em>(up to 51 health per level)</em>",
maxCount: 1, maxCount: 1,
count: 0, count: 0,
frequency: 1, frequency: 1,
@@ -2385,7 +2384,7 @@
allowed() { allowed() {
return tech.isExtraMaxEnergy return tech.isExtraMaxEnergy
}, },
requires: "inductive coupling", requires: "permittivity",
effect() { effect() {
tech.isEndLevelPowerUp = true; tech.isEndLevelPowerUp = true;
}, },
@@ -2535,6 +2534,29 @@
} }
} }
}, },
{
name: "inductive coupling",
description: "passive <strong class='color-f'>energy</strong> regen is increased by <strong>500%</strong><br>but you only regen when <strong>crouched</strong>",
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return tech.energyRegen !== 0
},
requires: "not ground state",
effect() {
tech.isCrouchRegen = true; //only used to check for requirements
m.regenEnergy = function() {
if (m.immuneCycle < m.cycle && m.crouch) m.energy += 5 * m.fieldRegen; //m.fieldRegen = 0.001
if (m.energy < 0) m.energy = 0
}
},
remove() {
tech.isCrouchRegen = false;
m.regenEnergy = m.regenEnergyDefault
}
},
{ {
name: "energy conservation", name: "energy conservation",
description: "<strong>5%</strong> of <strong class='color-d'>damage</strong> done recovered as <strong class='color-f'>energy</strong>", description: "<strong>5%</strong> of <strong class='color-d'>damage</strong> done recovered as <strong class='color-f'>energy</strong>",
@@ -4890,7 +4912,7 @@
allowed() { allowed() {
return !tech.isExtraMaxEnergy && (tech.haveGunCheck("drones") || tech.isForeverDrones || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && !(tech.isSporeField || tech.isMissileField || tech.isIceField))) return !tech.isExtraMaxEnergy && (tech.haveGunCheck("drones") || tech.isForeverDrones || (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" && !(tech.isSporeField || tech.isMissileField || tech.isIceField)))
}, },
requires: "drones, not inductive coupling", requires: "drones, not permittivity",
effect() { effect() {
tech.isDroneGrab = true tech.isDroneGrab = true
}, },
@@ -5655,7 +5677,7 @@
}, },
{ {
name: "expansion", name: "expansion",
description: "using <strong>standing wave</strong> field uses <strong class='color-f'>energy</strong><br>to temporarily <strong>expand</strong> its <strong>radius</strong>", description: "using <strong>standing wave</strong> field temporarily<br><strong>expands</strong> its <strong>radius</strong>",
// description: "use <strong class='color-f'>energy</strong> to <strong>expand</strong> <strong>standing wave</strong><br>the field slowly <strong>contracts</strong> when not used", // description: "use <strong class='color-f'>energy</strong> to <strong>expand</strong> <strong>standing wave</strong><br>the field slowly <strong>contracts</strong> when not used",
isFieldTech: true, isFieldTech: true,
maxCount: 1, maxCount: 1,
@@ -6956,10 +6978,10 @@
// }, // },
{ {
name: "planetesimals", name: "planetesimals",
description: `spawn a <strong class='color-m'>tech</strong> and play <strong>planetesimals</strong>,<br>an annoying asteroids game with Newtonian physics`, description: `play <strong>planetesimals</strong><br><em>(an annoying asteroids game with Newtonian physics)</em><br>clearing a <strong>level</strong> in <strong>planetesimals</strong> spawns a <strong class='color-m'>tech</strong> in <strong>n-gon</strong><br>but, if you <strong style="color:red;">die</strong> in <strong>planetesimals</strong> you <strong style="color:red;">die</strong> in <strong>n-gon</strong>`,
maxCount: 1, maxCount: 1,
count: 0, count: 0,
frequency: 0, frequency: 100,
isNonRefundable: true, isNonRefundable: true,
isExperimentHide: true, isExperimentHide: true,
isJunk: true, isJunk: true,
@@ -6969,7 +6991,24 @@
requires: "", requires: "",
effect() { effect() {
window.open('../../planetesimals/index.html', '_blank') window.open('../../planetesimals/index.html', '_blank')
powerUps.spawn(m.pos.x, m.pos.y, "tech"); // powerUps.spawn(m.pos.x, m.pos.y, "tech");
// for communicating to other tabs, like planetesimals
// Connection to a broadcast channel
const bc = new BroadcastChannel('planetesimals');
bc.activated = false
bc.onmessage = function(ev) {
if (ev.data === 'tech') powerUps.directSpawn(m.pos.x, m.pos.y, "tech");
if (ev.data === 'death') {
m.death()
bc.close(); //end session
}
if (ev.data === 'ready' && !bc.activated) {
bc.activated = true //prevents n-gon from activating multiple copies of planetesimals
bc.postMessage("activate");
}
}
}, },
remove() {} remove() {}
}, },
@@ -7096,9 +7135,7 @@
ctx.beginPath(); ctx.beginPath();
const vertices = mob[i].vertices; const vertices = mob[i].vertices;
ctx.moveTo(vertices[0].x, vertices[0].y); ctx.moveTo(vertices[0].x, vertices[0].y);
for (let j = 1, len = vertices.length; j < len; ++j) { for (let j = 1, len = vertices.length; j < len; ++j) ctx.quadraticCurveTo(mob[i].position.x, mob[i].position.y, vertices[j].x, vertices[j].y);
ctx.quadraticCurveTo(mob[i].position.x, mob[i].position.y, vertices[j].x, vertices[j].y);
}
ctx.quadraticCurveTo(mob[i].position.x, mob[i].position.y, vertices[0].x, vertices[0].y); ctx.quadraticCurveTo(mob[i].position.x, mob[i].position.y, vertices[0].x, vertices[0].y);
ctx.fillStyle = mob[i].fill; ctx.fillStyle = mob[i].fill;
ctx.strokeStyle = mob[i].stroke; ctx.strokeStyle = mob[i].stroke;
@@ -8824,5 +8861,6 @@
baseFx: null, baseFx: null,
isNeutronium: null, isNeutronium: null,
isFreeWormHole: null, isFreeWormHole: null,
isRewindField: null isRewindField: null,
isCrouchRegen: null
} }

View File

@@ -1,13 +1,28 @@
******************************************************** NEXT PATCH ************************************************** ******************************************************** NEXT PATCH **************************************************
grenades display their trajectory, to help you aim tech: inductive coupling - regen is increased by 500%, but you only regen when crouched
I'm might get rid of it, but for now we'll try it out
several duplication tech give slightly lower duplication chance tech gun turret gives 55% -> 60% harm reduction
strange attractor now properly includes all your tech in duplication chance (it wasn't updated for recent duplication tech) also I fixed a bug where it was giving 45% not 55%
old tech inductive coupling is renamed: permittivity
permittivity gives 3 -> 4 max energy per unused power up
1st ionization energy gives 6 -> 7 max energy per heal
tech expansion - no longer costs energy to expand standing wave field
JUNK tech planetesimals now can spawn tech in n-gon
or kill the player in n-gon
******************************************************** TODO ******************************************************** ******************************************************** TODO ********************************************************
tech: open a new tab for n-gon, spawn things in the original game based on events in new game
if you die in new die in original?
new is n-gon classic?
make a JUNK tech?
if you die in original open a tab with a new n-gon that starts on a random level with a random load out. if you clear the level you come back to life in the original?
give all duplicated power ups a half life that scales with the duplication chance give all duplicated power ups a half life that scales with the duplication chance
metastability reduces the half life metastability reduces the half life
how to communicate the half-life? how to communicate the half-life?