horizontal flip

levels are now randomly flipped horizontally

removed spawn.boost( from n-gon
make boosts with these commands:
  const boost1 = level.boost(2550, 1500, 1700) //x,y, boost height
  const boost2 = level.boost(-3400, -2050, 3000)
  level.custom = () => {
      boost1.query();
      boost2.query();
also you don't have to draw the boosts any more, the query command does it for you
This commit is contained in:
landgreen
2021-06-01 05:56:15 -07:00
parent 69fec1cde7
commit 05420af818
6 changed files with 960 additions and 655 deletions

BIN
.DS_Store vendored

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -1917,8 +1917,6 @@ const m = {
player.force.y = 0
}
Engine.update(engine, simulation.delta);
// level.checkZones();
// level.checkQuery();
m.move();
simulation.checks();
// mobs.loop();

View File

@@ -12,8 +12,6 @@ const simulation = {
} else {
m.airControl()
}
// level.checkZones();
level.checkQuery();
m.move();
m.look();
simulation.checks();
@@ -51,8 +49,6 @@ const simulation = {
} else {
m.airControl()
}
// level.checkZones();
level.checkQuery();
m.move();
m.look();
simulation.checks();
@@ -83,9 +79,6 @@ const simulation = {
} else {
m.airControl()
}
level.checkZones();
level.checkQuery();
m.move();
simulation.checks();
mobs.loop();
@@ -518,7 +511,7 @@ const simulation = {
}
m.look = m.lookDefault
simulation.isHorizontalFlipped = Math.random() < 0.5 ? true : false //if true, some maps are flipped horizontally
level.levels = level.playableLevels.slice(0) //copy array, not by just by assignment
if (simulation.isCommunityMaps) {
level.levels.push("stronghold");
@@ -721,7 +714,6 @@ const simulation = {
m.drop();
m.hole.isOn = false;
level.zones = [];
level.queryList = [];
simulation.drawList = [];
function removeAll(array) {
@@ -1044,18 +1036,6 @@ const simulation = {
ctx.stroke();
},
testing() {
//query zones
// ctx.beginPath();
// for (let i = 0, len = level.queryList.length; i < len; ++i) {
// ctx.rect(
// level.queryList[i].bounds.max.x,
// level.queryList[i].bounds.max.y,
// level.queryList[i].bounds.min.x - level.queryList[i].bounds.max.x,
// level.queryList[i].bounds.min.y - level.queryList[i].bounds.max.y
// );
// }
// ctx.fillStyle = "rgba(0, 0, 255, 0.2)";
// ctx.fill();
//jump
ctx.beginPath();
let bodyDraw = jumpSensor.vertices;

View File

@@ -2,25 +2,25 @@
const spawn = {
pickList: ["starter", "starter"],
fullPickList: [
"hopper", "hopper", "hopper",
"shooter", "shooter",
"striker", "striker",
"laser", "laser",
"exploder", "exploder",
"stabber", "stabber",
"launcher", "launcher",
// "hopper", "hopper", "hopper",
// "shooter", "shooter",
// "striker", "striker",
// "laser", "laser",
// "exploder", "exploder",
// "stabber", "stabber",
// "launcher", "launcher",
"springer", "springer",
"pulsar", "pulsar",
"sucker",
"chaser",
"sniper",
"spinner",
"grower",
"beamer",
"focuser",
"spawner",
"ghoster",
"sneaker",
// "pulsar", "pulsar",
// "sucker",
// "chaser",
// "sniper",
// "spinner",
// "grower",
// "beamer",
// "focuser",
// "spawner",
// "ghoster",
// "sneaker",
],
allowedGroupList: ["chaser", "spinner", "striker", "springer", "laser", "focuser", "beamer", "exploder", "spawner", "shooter", "launcher", "stabber", "sniper", "pulsar"],
setSpawnList() { //this is run at the start of each new level to determine the possible mobs for the level
@@ -226,6 +226,19 @@ const spawn = {
finalBoss(x, y, radius = 300) {
mobs.spawn(x, y, 6, radius, "rgb(150,150,255)");
let me = mob[mob.length - 1];
setTimeout(() => { //fix mob in place, but allow rotation
me.constraint = Constraint.create({
pointA: {
x: me.position.x,
y: me.position.y
},
bodyB: me,
stiffness: 0.001,
damping: 1
});
World.add(engine.world, me.constraint);
}, 2000); //add in a delay in case the level gets flipped left right
me.isBoss = true;
me.frictionAir = 0.01;
me.memory = Infinity;
@@ -351,14 +364,14 @@ const spawn = {
me.totalCycles = 0
me.mode = 0;
me.do = function() {
Matter.Body.setPosition(this, { //hold position
x: x,
y: y
});
Matter.Body.setVelocity(this, {
x: 0,
y: 0
});
// Matter.Body.setPosition(this, {
// x: x,
// y: y
// });
// Matter.Body.setVelocity(this, {
// x: 0,
// y: 0
// });
this.modeDo(); //this does different things based on the mode
this.checkStatus();
this.cycle++; //switch modes÷
@@ -979,18 +992,17 @@ const spawn = {
World.add(engine.world, cons[cons.length - 1]);
cons[len2].length = 100 + 1.5 * radius;
me.cons2 = cons[len2];
me.onDeath = function() {
this.removeCons();
};
spawn.shield(me, x, y);
me.do = function() {
this.gravity();
this.searchSpring();
this.checkStatus();
this.springAttack();
};
me.onDeath = function() {
this.removeCons();
};
spawn.shield(me, x, y);
},
hopper(x, y, radius = 30 + Math.ceil(Math.random() * 30)) {
mobs.spawn(x, y, 5, radius, "rgb(0,200,180)");
@@ -1308,11 +1320,6 @@ const spawn = {
World.add(engine.world, cons[cons.length - 1]);
cons[len2].length = 100 + 1.5 * radius;
me.cons2 = cons[len2];
me.onDeath = function() {
this.removeCons();
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
};
me.do = function() {
this.gravity();
this.searchSpring();
@@ -1320,6 +1327,11 @@ const spawn = {
this.springAttack();
};
me.onDeath = function() {
this.removeCons();
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
};
radius = 22 // radius of each node mob
const sideLength = 100 // distance between each node mob
const nodes = 6
@@ -1349,88 +1361,88 @@ const spawn = {
spawn.groupShield(targets, x, y, sideLength + 1 * radius + nodes * 5 - 25);
spawn.allowShields = true;
},
timeSkipBoss(x, y, radius = 55) {
mobs.spawn(x, y, 6, radius, '#000');
let me = mob[mob.length - 1];
me.isBoss = true;
// me.stroke = "transparent"; //used for drawSneaker
me.timeSkipLastCycle = 0
me.eventHorizon = 1800; //required for black hole
me.seeAtDistance2 = (me.eventHorizon + 2000) * (me.eventHorizon + 2000); //vision limit is event horizon + 2000
me.accelMag = 0.0004 * simulation.accelScale;
// me.frictionAir = 0.005;
// me.memory = 1600;
// Matter.Body.setDensity(me, 0.02); //extra dense //normal is 0.001 //makes effective life much larger
Matter.Body.setDensity(me, 0.0005 + 0.00018 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
spawn.shield(me, x, y, 1);
// timeSkipBoss(x, y, radius = 55) {
// mobs.spawn(x, y, 6, radius, '#000');
// let me = mob[mob.length - 1];
// me.isBoss = true;
// // me.stroke = "transparent"; //used for drawSneaker
// me.timeSkipLastCycle = 0
// me.eventHorizon = 1800; //required for black hole
// me.seeAtDistance2 = (me.eventHorizon + 2000) * (me.eventHorizon + 2000); //vision limit is event horizon + 2000
// me.accelMag = 0.0004 * simulation.accelScale;
// // me.frictionAir = 0.005;
// // me.memory = 1600;
// // Matter.Body.setDensity(me, 0.02); //extra dense //normal is 0.001 //makes effective life much larger
// Matter.Body.setDensity(me, 0.0005 + 0.00018 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
// spawn.shield(me, x, y, 1);
me.onDeath = function() {
//applying forces to player doesn't seem to work inside this method, not sure why
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
};
me.do = function() {
//keep it slow, to stop issues from explosion knock backs
if (this.speed > 8) {
Matter.Body.setVelocity(this, {
x: this.velocity.x * 0.99,
y: this.velocity.y * 0.99
});
}
this.seePlayerCheck();
this.checkStatus();
this.attraction()
if (!simulation.isTimeSkipping) {
const compress = 1
if (this.timeSkipLastCycle < simulation.cycle - compress &&
Vector.magnitude(Vector.sub(this.position, player.position)) < this.eventHorizon) {
this.timeSkipLastCycle = simulation.cycle
simulation.timeSkip(compress)
// me.onDeath = function() {
// //applying forces to player doesn't seem to work inside this method, not sure why
// powerUps.spawnBossPowerUp(this.position.x, this.position.y)
// };
// me.do = function() {
// //keep it slow, to stop issues from explosion knock backs
// if (this.speed > 8) {
// Matter.Body.setVelocity(this, {
// x: this.velocity.x * 0.99,
// y: this.velocity.y * 0.99
// });
// }
// this.seePlayerCheck();
// this.checkStatus();
// this.attraction()
// if (!simulation.isTimeSkipping) {
// const compress = 1
// if (this.timeSkipLastCycle < simulation.cycle - compress &&
// Vector.magnitude(Vector.sub(this.position, player.position)) < this.eventHorizon) {
// this.timeSkipLastCycle = simulation.cycle
// simulation.timeSkip(compress)
this.fill = `rgba(0,0,0,${0.4+0.6*Math.random()})`
this.stroke = "#014"
this.isShielded = false;
this.isDropPowerUp = true;
this.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob; //can't touch bullets
ctx.beginPath();
ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI);
ctx.fillStyle = "#fff";
ctx.globalCompositeOperation = "destination-in"; //in or atop
ctx.fill();
ctx.globalCompositeOperation = "source-over";
ctx.beginPath();
ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI);
ctx.clip();
// this.fill = `rgba(0,0,0,${0.4+0.6*Math.random()})`
// this.stroke = "#014"
// this.isShielded = false;
// this.isDropPowerUp = true;
// this.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob; //can't touch bullets
// ctx.beginPath();
// ctx.arc(this.position.x, this.position.y, 9999, 0, 2 * Math.PI);
// ctx.fillStyle = "#000";
// ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI);
// ctx.fillStyle = "#fff";
// ctx.globalCompositeOperation = "destination-in"; //in or atop
// ctx.fill();
// ctx.strokeStyle = "#000";
// ctx.stroke();
// ctx.globalCompositeOperation = "source-over";
// ctx.beginPath();
// ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI);
// ctx.clip();
// // ctx.beginPath();
// // ctx.arc(this.position.x, this.position.y, 9999, 0, 2 * Math.PI);
// // ctx.fillStyle = "#000";
// // ctx.fill();
// // ctx.strokeStyle = "#000";
// // ctx.stroke();
// // ctx.beginPath();
// // ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI);
// // ctx.fillStyle = `rgba(0,0,0,${0.05*Math.random()})`;
// // ctx.fill();
// // ctx.strokeStyle = "#000";
// // ctx.stroke();
// } else {
// this.isShielded = true;
// this.isDropPowerUp = false;
// this.seePlayer.recall = false
// this.fill = "transparent"
// this.stroke = "transparent"
// this.collisionFilter.mask = cat.player | cat.map | cat.body | cat.mob; //can't touch bullets
// ctx.beginPath();
// ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI);
// ctx.fillStyle = `rgba(0,0,0,${0.05*Math.random()})`;
// ctx.fill();
// ctx.strokeStyle = "#000";
// ctx.stroke();
} else {
this.isShielded = true;
this.isDropPowerUp = false;
this.seePlayer.recall = false
this.fill = "transparent"
this.stroke = "transparent"
this.collisionFilter.mask = cat.player | cat.map | cat.body | cat.mob; //can't touch bullets
ctx.beginPath();
ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI);
ctx.fillStyle = `rgba(0,0,0,${0.05*Math.random()})`;
ctx.fill();
}
}
}
},
// }
// }
// }
// },
beamer(x, y, radius = 15 + Math.ceil(Math.random() * 15)) {
mobs.spawn(x, y, 4, radius, "rgb(255,0,190)");
let me = mob[mob.length - 1];
@@ -1570,13 +1582,14 @@ const spawn = {
const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x);
this.force.x += forceMag * Math.cos(angle);
this.force.y += forceMag * Math.sin(angle);
} else {
}
// else {
//high friction if can't lock onto player
// Matter.Body.setVelocity(this, {
// x: this.velocity.x * 0.98,
// y: this.velocity.y * 0.98
// });
}
// }
if (dist2 > 80000) {
const laserWidth = 0.002;
let laserOffR = Vector.rotateAbout(this.laserPos, (targetDist - r) * laserWidth, this.position);
@@ -1739,12 +1752,26 @@ const spawn = {
pulsarBoss(x, y, radius = 90) {
mobs.spawn(x, y, 3, radius, "#a0f");
let me = mob[mob.length - 1];
setTimeout(() => { //fix mob in place, but allow rotation
me.constraint = Constraint.create({
pointA: {
x: me.position.x,
y: me.position.y
},
bodyB: me,
stiffness: 0.001,
damping: 1
});
World.add(engine.world, me.constraint);
}, 2000); //add in a delay in case the level gets flipped left right
me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front
Matter.Body.rotate(me, Math.random() * Math.PI * 2);
me.radius *= 1.5
me.vertices[1].x = me.position.x + Math.cos(me.angle) * me.radius; //make one end of the triangle longer
me.vertices[1].y = me.position.y + Math.sin(me.angle) * me.radius;
me.homePosition = { x: x, y: y };
// me.homePosition = { x: x, y: y };
me.fireCycle = 0
me.fireTarget = { x: 0, y: 0 }
me.pulseRadius = Math.min(500, 230 + simulation.difficulty * 3)
@@ -1836,9 +1863,9 @@ const spawn = {
}
}
//gently return to starting location
const sub = Vector.sub(this.homePosition, this.position)
const dist = Vector.magnitude(sub)
if (dist > 250) this.force = Vector.mult(Vector.normalise(sub), this.mass * 0.0002)
// const sub = Vector.sub(this.homePosition, this.position)
// const dist = Vector.magnitude(sub)
// if (dist > 250) this.force = Vector.mult(Vector.normalise(sub), this.mass * 0.0002)
} else {
this.isFiring = false
}
@@ -1848,12 +1875,26 @@ const spawn = {
pulsar(x, y, radius = 40) {
mobs.spawn(x, y, 3, radius, "#f08");
let me = mob[mob.length - 1];
setTimeout(() => { //fix mob in place, but allow rotation
me.constraint = Constraint.create({
pointA: {
x: me.position.x,
y: me.position.y
},
bodyB: me,
stiffness: 0.0001,
damping: 1
});
World.add(engine.world, me.constraint);
}, 2000); //add in a delay in case the level gets flipped left right
me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front
Matter.Body.rotate(me, Math.random() * Math.PI * 2);
me.radius *= 2
me.vertices[1].x = me.position.x + Math.cos(me.angle) * me.radius; //make one end of the triangle longer
me.vertices[1].y = me.position.y + Math.sin(me.angle) * me.radius;
me.homePosition = { x: x, y: y };
// me.homePosition = { x: x, y: y };
Matter.Body.setDensity(me, 0.002); //extra dense //normal is 0.001 //makes effective life much larger
me.fireCycle = Infinity
me.fireTarget = { x: 0, y: 0 }
@@ -1960,9 +2001,9 @@ const spawn = {
}
}
//gently return to starting location
const sub = Vector.sub(this.homePosition, this.position)
const dist = Vector.magnitude(sub)
if (dist > 350) this.force = Vector.mult(Vector.normalise(sub), this.mass * 0.0002)
// const sub = Vector.sub(this.homePosition, this.position)
// const dist = Vector.magnitude(sub)
// if (dist > 350) this.force = Vector.mult(Vector.normalise(sub), this.mass * 0.0002)
} else {
this.isFiring = false
}
@@ -1989,11 +2030,25 @@ const spawn = {
laserBoss(x, y, radius = 30) {
mobs.spawn(x, y, 3, radius, "#f00");
let me = mob[mob.length - 1];
setTimeout(() => { //fix mob in place, but allow rotation
me.constraint = Constraint.create({
pointA: {
x: me.position.x,
y: me.position.y
},
bodyB: me,
stiffness: 0.001,
damping: 1
});
World.add(engine.world, me.constraint);
}, 2000); //add in a delay in case the level gets flipped left right
me.isBoss = true;
me.startingPosition = {
x: x,
y: y
}
// me.startingPosition = {
// x: x,
// y: y
// }
me.count = 0;
me.frictionAir = 0.03;
// me.torque -= me.inertia * 0.002
@@ -2039,11 +2094,11 @@ const spawn = {
}
Matter.Body.setVelocity(this, {
x: 0,
y: 0
});
Matter.Body.setPosition(this, this.startingPosition);
// Matter.Body.setVelocity(this, {
// x: 0,
// y: 0
// });
// Matter.Body.setPosition(this, this.startingPosition);
};
me.laser = function(where, angle) {
@@ -2487,14 +2542,27 @@ const spawn = {
shooterBoss(x, y, radius = 110) {
mobs.spawn(x, y, 3, radius, "rgb(255,70,180)");
let me = mob[mob.length - 1];
setTimeout(() => { //fix mob in place, but allow rotation
me.constraint = Constraint.create({
pointA: {
x: me.position.x,
y: me.position.y
},
bodyB: me,
stiffness: 0.0002,
damping: 1
});
World.add(engine.world, me.constraint);
}, 2000); //add in a delay in case the level gets flipped left right
me.isBoss = true;
me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front
me.isVerticesChange = true
me.memory = 240;
me.homePosition = {
x: x,
y: y
};
// me.homePosition = {
// x: x,
// y: y
// };
me.fireFreq = 0.025;
me.noseLength = 0;
me.fireAngle = 0;
@@ -2516,9 +2584,9 @@ const spawn = {
this.checkStatus();
this.fire();
//gently return to starting location
const sub = Vector.sub(this.homePosition, this.position)
const dist = Vector.magnitude(sub)
if (dist > 50) this.force = Vector.mult(Vector.normalise(sub), this.mass * 0.0002)
// const sub = Vector.sub(this.homePosition, this.position)
// const dist = Vector.magnitude(sub)
// if (dist > 50) this.force = Vector.mult(Vector.normalise(sub), this.mass * 0.0002)
};
},
bullet(x, y, radius = 9, sides = 0) {
@@ -2811,6 +2879,19 @@ const spawn = {
shieldingBoss(x, y, radius = 200) {
mobs.spawn(x, y, 9, radius, "rgb(150, 150, 255)");
let me = mob[mob.length - 1];
setTimeout(() => { //fix mob in place, but allow rotation
me.constraint = Constraint.create({
pointA: {
x: me.position.x,
y: me.position.y
},
bodyB: me,
stiffness: 0.001,
damping: 1
});
World.add(engine.world, me.constraint);
}, 2000); //add in a delay in case the level gets flipped left right
Matter.Body.rotate(me, Math.random() * 2 * Math.PI)
// me.stroke = "rgb(220,220,255)"
me.isBoss = true;
@@ -2819,7 +2900,7 @@ const spawn = {
me.frictionStatic = 0;
me.friction = 0;
me.frictionAir = 0.5;
me.homePosition = { x: x, y: y };
// me.homePosition = { x: x, y: y };
spawn.shield(me, x, y, 1);
spawn.spawnOrbitals(me, radius + 50 + 200 * Math.random())
@@ -2862,9 +2943,9 @@ const spawn = {
ctx.strokeStyle = "rgba(200,200,255,0.9)"
ctx.stroke();
//return to starting location
const sub = Vector.sub(this.homePosition, this.position)
const dist = Vector.magnitude(sub)
if (dist > 350) this.force = Vector.mult(Vector.normalise(sub), this.mass * 0.05)
// const sub = Vector.sub(this.homePosition, this.position)
// const dist = Vector.magnitude(sub)
// if (dist > 350) this.force = Vector.mult(Vector.normalise(sub), this.mass * 0.05)
}
}
};
@@ -3185,6 +3266,7 @@ const spawn = {
stiffness: 0.00012
});
World.add(engine.world, cons[cons.length - 1]);
spawn.shield(me, x, y, 1);
setTimeout(() => { spawn.spawnOrbitals(me, radius + 50 + 200 * Math.random()) }, 100); //have to wait a sec so the tether constraint doesn't attach to an orbital
me.onDeath = function() {

View File

@@ -1,11 +1,15 @@
******************************************************** NEXT PATCH ********************************************************
added 50% chance for elevators on warehouse level
levels are now randomly flipped horizontally
metamaterial cloaking now does 300% more damage if a mob has not died in the last 4 seconds
removed: tech: combinatorial optimization - increase damage by 66% if a mob hasn't died in the last 5 seconds
fixed bug with experiment not loading tech
removed spawn.boost( from n-gon
make boosts with these commands:
const boost1 = level.boost(2550, 1500, 1700) //x,y, boost height
const boost2 = level.boost(-3400, -2050, 3000)
level.custom = () => {
boost1.query();
boost2.query();
also you don't have to draw the boosts any more, the query command does it for you
******************************************************** BUGS ********************************************************
@@ -16,11 +20,7 @@ figure out how to undo ship mode
Why does micro-extruder lag so much
blue triangle boss can move backwards and aim away from you if set up properly
HTML build system looks bad since tech does grey out
you have to press z once to get copy to work for simulation.enableConstructMode() sometimes
not sure how to reproduce, but it happens often on the first draw
issues with dot product probably, but might not be worth fixing
mouse event e.which is deprecated
@@ -35,8 +35,14 @@ is there a way to check if the player is stuck inside the map or block
******************************************************** TODO ********************************************************
MACHOs might clash with cloaking field graphic
buttons can now on/off boosts
drones should check for power ups even if there are mobs nearby
but not travel towards power ups
Weak Anthropic Principle: you get a second chance at life, but now the game has falling damage!
tech: supersaturation is buffed but add falling damage
tech: increase health and remove air control
things to avoid when designing a map:
avoid a single path through the map
@@ -51,31 +57,15 @@ avoid large flat areas; this doesn't produce fun combat
instead produce complex places for the player to hide
break these rules when its important to make a statement in your level
flip left right on some maps
some mobs use the original x parameter in their loop, but it doesn't get flipped
manually edit each mob's logic
finalBoss, shooters?
tech: supersaturation is buffed but add falling damage
mob: molecule shapes - 2 separate mobs joined by a bond
use constraints: just spawn 2x or 3x groupings
low friction so they can spin around
spin when attacking player?
increase constraint length when attacking
make most future tech for guns / fields
tech: mine - fire the mine into where you were in the past
maybe it could check all your past locations and explode there if there is something in range
tech: increase health and harm taken
remove air control
negative tech aspect, junk , experiment?
tech: use the ability for power ups to have custom code
(note: this code is half way done, it just needs to be completed)
attracted to player
@@ -86,10 +76,6 @@ tech: wormhole through walls?
pause should show the last in game console message
general idea: let the player use research more like money
spend it to do things
buff some special tech and add a research cost
tech: picking up heal power ups when at full health does harm equal to the heal values
benefit on pick up:
get ammo
@@ -105,8 +91,6 @@ nail-gun, or ....
current location or location when fired?
explode when turning back
Tech: "Quantum Tunneling" Foam travels through blocks and walls 50% faster.
make a tech that improves all charge guns
for: pulse, foam, rail gun
effect:
@@ -121,7 +105,6 @@ apply the new gun.do functions to other guns
works similar to foam
performance issues?
tech plasma field - plasma field becomes an aoe damage field with the same radius
200% more energy drain, 100% more damage
draw a square (or two) that rapidly spins