2 more classic n-gon dates

added 2 more classic n-gon dates

plasma ball
  does 10% more damage
  moves 20% faster
  targets mob bullets better

standing wave has a 45/60->30/60 second cooldown after blocking a shielded mob
  but, standing wave now also triggers it's CD on shields that protect groups of mobs

JUNK tech: Mech v4.48 removed
JUNK tech: cosmogonic myth - opens a random classic version of n-gon in a new tab, after 5 minutes close the tab and spawn 1 of every tech

bug fixes
This commit is contained in:
landgreen
2022-04-09 14:17:55 -07:00
parent 78570d06a6
commit 2a5a4781a9
10 changed files with 227 additions and 104 deletions

View File

@@ -120,6 +120,8 @@
<option value="classic/4-15-2018/">n-gon: 2018</option>
<option value="classic/7-11-2019/">n-gon: summer-2019</option>
<option value="classic/9-8-2019/">n-gon: fall-2019</option>
<option value="classic/7-15-2020/">n-gon: summer-2020</option>
<option value="classic/6-1-2021/">n-gon: spring-2021</option>
<option value="" selected>current version</option>
</select>
<br>

View File

@@ -1531,25 +1531,6 @@ const b = {
})
let dist = Vector.magnitude(sub)
if (input.fire) {
//control position while hooked
// if (input.down) { //down
// player.force.y += 5 * player.mass * simulation.g;
// dist *= 0.25
// this.ropeExtension += 10
// } else if (input.up) { //up
// this.ropeExtension -= 10
// if (this.ropeExtension < 0) this.ropeExtension = 0
// player.force.y -= 5 * player.mass * simulation.g;
// dist *= 0.4
// } else {}
// if (input.right) { //down
// dist *= 0.4
// player.force.x += 5 * player.mass * simulation.g;
// } else if (input.left) { //up
// dist *= 0.4
// player.force.x -= 5 * player.mass * simulation.g;
// }
m.fireCDcycle = m.cycle + 30; // cool down if out of energy
this.endCycle = simulation.cycle + 10
if (input.down) { //down
@@ -1608,7 +1589,7 @@ const b = {
});
Composite.add(engine.world, bullet[me]); //add bullet to world
},
harpoon(where, target, angle = m.angle, harpoonSize = 1, isReturn = false, totalCycles = 35) {
harpoon(where, target, angle = m.angle, harpoonSize = 1, isReturn = false, totalCycles = 35, isReturnAmmo = true) {
const me = bullet.length;
const returnRadius = 100 * Math.sqrt(harpoonSize)
bullet[me] = Bodies.fromVertices(where.x, where.y, [{ x: -40 * harpoonSize, y: 2 * harpoonSize, index: 0, isInternal: false }, { x: -40 * harpoonSize, y: -2 * harpoonSize, index: 1, isInternal: false }, { x: 50 * harpoonSize, y: -3 * harpoonSize, index: 3, isInternal: false }, { x: 30 * harpoonSize, y: 2 * harpoonSize, index: 4, isInternal: false }], {
@@ -1723,6 +1704,7 @@ const b = {
player.force.x += momentum.x
player.force.y += momentum.y
// refund ammo
if (isReturnAmmo) {
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "harpoon") {
b.guns[i].ammo++;
@@ -1730,6 +1712,7 @@ const b = {
break;
}
}
}
} else {
if (!tech.isRailEnergyGain && m.energy > 0.005) m.energy -= 0.005
const sub = Vector.sub(this.position, m.pos)
@@ -6404,7 +6387,7 @@ const b = {
}
}
if (input.down) {
b.harpoon(where, null, m.angle, harpoonSize, true, 1.5 * totalCycles)
b.harpoon(where, null, m.angle, harpoonSize, true, 1.5 * totalCycles, (input.down && tech.crouchAmmoCount && (tech.crouchAmmoCount - 1) % 2) ? false : true)
} else {
b.harpoon(where, closest.target, m.angle, harpoonSize, true, totalCycles)
}

View File

@@ -1252,7 +1252,9 @@ if (localSettings.isAllowed && !localSettings.isEmpty) {
document.getElementById("fps-select").value = localSettings.fpsCapDefault
} else {
console.log('setting default localSettings')
const isAllowed = localSettings.isAllowed //don't overwrite isAllowed value
localSettings = {
isAllowed: isAllowed,
personalSeeds: [],
isJunkExperiment: false,
isCommunityMaps: false,

View File

@@ -17,10 +17,13 @@ const level = {
if (level.levelsCleared === 0) { //this code only runs on the first level
// simulation.isHorizontalFlipped = true
// m.setField("metamaterial cloaking")
// b.giveGuns("harpoon")
// b.giveGuns("drones")
// tech.giveTech("desublimated ammunition")
// tech.giveTech("smelting")
// tech.giveTech("smelting")
// tech.giveTech("616")
// tech.giveTech("grappling hook")
// tech.giveTech("discount")
// tech.giveTech("shape-memory alloy")
// tech.giveTech("coyote")
// for (let i = 0; i < 2; i++) powerUps.directSpawn(0, 0, "tech");
// for (let i = 0; i < 2; i++) tech.giveTech("corona discharge")
// for (let i = 10; i < tech.tech.length; i++) { tech.tech[i].isBanished = true }
@@ -112,10 +115,7 @@ const level = {
if ((tech.isRelay || tech.isFlipFlop) && !tech.isFlipFlopOn) {
tech.isFlipFlopOn = true
if (tech.isFlipFlopHealth) m.setMaxHealth()
if (tech.isRelayEnergy) {
m.setMaxEnergy()
m.energy += 2
}
if (tech.isRelayEnergy) m.setMaxEnergy()
m.eyeFillColor = m.fieldMeterColor
simulation.makeTextLog(`tech.isFlipFlopOn <span class='color-symbol'>=</span> true`);
}

View File

@@ -233,6 +233,7 @@ const m = {
},
buttonCD_jump: 0, //cool down for player buttons
jump() {
// if (!m.onGround) m.lastOnGroundCycle = 0 //m.cycle - tech.coyoteTime
m.buttonCD_jump = m.cycle; //can't jump again until 20 cycles pass
//apply a fraction of the jump force to the body the player is jumping off of
Matter.Body.applyForce(m.standingOn, m.pos, {
@@ -287,6 +288,7 @@ const m = {
},
airControl() {
//check for coyote time jump
// if (input.up && m.buttonCD_jump + 20 + tech.coyoteTime < m.cycle && m.yOffWhen.stand > 23 && m.lastOnGroundCycle + tech.coyoteTime > m.cycle) m.jump()
if (input.up && m.buttonCD_jump + 20 < m.cycle && m.yOffWhen.stand > 23 && m.lastOnGroundCycle + 5 > m.cycle) m.jump()
//check for short jumps //moving up //recently pressed jump //but not pressing jump key now
@@ -969,7 +971,7 @@ const m = {
}
},
setMaxEnergy() {
m.maxEnergy = (tech.isMaxEnergyTech ? 0.5 : 1) + tech.bonusEnergy + tech.healMaxEnergyBonus + tech.harmonicEnergy + 2 * tech.isGroundState + 2 * tech.isRelay * tech.isFlipFlopOn * tech.isRelayEnergy
m.maxEnergy = (tech.isMaxEnergyTech ? 0.5 : 1) + tech.bonusEnergy + tech.healMaxEnergyBonus + tech.harmonicEnergy + 2 * tech.isGroundState + 3 * tech.isRelay * tech.isFlipFlopOn * tech.isRelayEnergy
simulation.makeTextLog(`<span class='color-var'>m</span>.<span class='color-f'>maxEnergy</span> <span class='color-symbol'>=</span> ${(m.maxEnergy.toFixed(2))}`)
},
fieldMeterColor: "#0cf",
@@ -1558,7 +1560,7 @@ const m = {
m.pushMass(mob[i]);
this.drainCD = m.cycle + 10
}
if (mob[i].isShielded) m.fieldCDcycle = m.cycle + 45
if (mob[i].isShielded || mob[i].shield) m.fieldCDcycle = m.cycle + 30
}
}
}
@@ -1587,7 +1589,7 @@ const m = {
m.pushMass(mob[i]);
this.drainCD = m.cycle + 10
}
if (mob[i].isShielded) m.fieldCDcycle = m.cycle + 45
if (mob[i].isShielded || mob[i].shield) m.fieldCDcycle = m.cycle + 30
}
}
}
@@ -2111,14 +2113,14 @@ const m = {
isOn: false,
drain: 0.0015,
radiusLimit: 10,
damage: 0.6,
damage: 0.7,
setPositionToNose() {
const nose = { x: m.pos.x + 10 * Math.cos(m.angle), y: m.pos.y + 10 * Math.sin(m.angle) }
Matter.Body.setPosition(this, Vector.add(nose, Vector.mult(Vector.normalise(Vector.sub(nose, m.pos)), this.circleRadius)));
},
fire() {
this.isAttached = false;
const speed = 6 //scale with mass?
const speed = 7 //scale with mass?
Matter.Body.setVelocity(this, {
x: player.velocity.x * 0.4 + speed * Math.cos(m.angle),
y: speed * Math.sin(m.angle)
@@ -2194,7 +2196,7 @@ const m = {
const arcList = []
const dischargeRange = 150 + 1600 * tech.plasmaDischarge + 1.3 * this.circleRadius
for (let i = 0, len = mob.length; i < len; i++) {
if (!mob[i].isBadTarget && mob[i].alive) {
if (mob[i].alive && (!mob[i].isBadTarget || mob[i].isMobBullet)) {
const sub = Vector.magnitude(Vector.sub(this.position, mob[i].position))
if (sub < this.circleRadius + mob[i].radius) {
if (!this.isAttached && !mob[i].isMobBullet) this.isPopping = true
@@ -2251,8 +2253,8 @@ const m = {
//slowly slow down if too fast
if (this.speed > 8) {
const scale = 0.997
if (this.speed > 10) {
const scale = 0.998
Matter.Body.setVelocity(this, {
x: scale * this.velocity.x,
y: scale * this.velocity.y
@@ -2744,8 +2746,44 @@ const m = {
// m.fieldDamage = 2.46 // 1 + 146/100
m.fieldDrawRadius = 0
m.isSneakAttack = true;
const drawRadius = 900
const drawRadius = 800
m.drawCloak = function() {
m.fieldPhase += 0.007
const wiggle = 0.15 * Math.sin(m.fieldPhase * 0.5)
ctx.beginPath();
ctx.ellipse(m.pos.x, m.pos.y, m.fieldDrawRadius * (1 - wiggle), m.fieldDrawRadius * (1 + wiggle), m.fieldPhase, 0, 2 * Math.PI);
// if (m.fireCDcycle > m.cycle && (input.field)) {}
ctx.fillStyle = "#fff"
ctx.lineWidth = 2;
ctx.strokeStyle = "#000"
ctx.stroke()
// ctx.fillStyle = "#fff" //`rgba(0,0,0,${0.5+0.5*m.energy})`;
ctx.globalCompositeOperation = "destination-in";
ctx.fill();
ctx.globalCompositeOperation = "source-over";
ctx.clip();
}
// m.drawCloak = function() { //controlled by player look direction
// m.fieldPhase = m.angle
// const wiggle = 0.15 * Math.sin(m.angle)
// const off = {
// x: Math.cos(m.angle),
// y: Math.sin(m.angle)
// }
// const look = Vector.add(m.pos, Vector.mult(off, 500))
// ctx.beginPath();
// ctx.ellipse(look.x, look.y, m.fieldDrawRadius * (1 - wiggle), m.fieldDrawRadius * (1 + wiggle), m.fieldPhase, 0, 2 * Math.PI);
// // if (m.fireCDcycle > m.cycle && (input.field)) {}
// ctx.fillStyle = "#fff"
// ctx.lineWidth = 2;
// ctx.strokeStyle = "#000"
// ctx.stroke()
// // ctx.fillStyle = "#fff" //`rgba(0,0,0,${0.5+0.5*m.energy})`;
// ctx.globalCompositeOperation = "destination-in";
// ctx.fill();
// ctx.globalCompositeOperation = "source-over";
// ctx.clip();
// }
m.hold = function() {
// console.log(m.holdingTarget)
if (m.isHolding) {
@@ -2805,32 +2843,32 @@ const m = {
}
}
function drawField() {
m.fieldPhase += 0.007
const wiggle = 0.15 * Math.sin(m.fieldPhase * 0.5)
ctx.beginPath();
ctx.ellipse(m.pos.x, m.pos.y, m.fieldDrawRadius * (1 - wiggle), m.fieldDrawRadius * (1 + wiggle), m.fieldPhase, 0, 2 * Math.PI);
// if (m.fireCDcycle > m.cycle && (input.field)) {}
ctx.fillStyle = "#fff"
ctx.lineWidth = 2;
ctx.strokeStyle = "#000"
ctx.stroke()
// ctx.fillStyle = "#fff" //`rgba(0,0,0,${0.5+0.5*m.energy})`;
ctx.globalCompositeOperation = "destination-in";
ctx.fill();
ctx.globalCompositeOperation = "source-over";
ctx.clip();
}
// function drawField() {
// m.fieldPhase += 0.007
// const wiggle = 0.15 * Math.sin(m.fieldPhase * 0.5)
// ctx.beginPath();
// ctx.ellipse(m.pos.x, m.pos.y, m.fieldDrawRadius * (1 - wiggle), m.fieldDrawRadius * (1 + wiggle), m.fieldPhase, 0, 2 * Math.PI);
// // if (m.fireCDcycle > m.cycle && (input.field)) {}
// ctx.fillStyle = "#fff"
// ctx.lineWidth = 2;
// ctx.strokeStyle = "#000"
// ctx.stroke()
// // ctx.fillStyle = "#fff" //`rgba(0,0,0,${0.5+0.5*m.energy})`;
// ctx.globalCompositeOperation = "destination-in";
// ctx.fill();
// ctx.globalCompositeOperation = "source-over";
// ctx.clip();
// }
// const energy = Math.max(0.01, Math.min(m.energy, 1))
if (m.isCloak) {
this.fieldRange = this.fieldRange * 0.9 + 0.1 * drawRadius
m.fieldDrawRadius = this.fieldRange * 0.88 //* Math.min(1, 0.3 + 0.5 * Math.min(1, energy * energy));
drawField()
} else if (this.fieldRange < 3000) {
m.drawCloak()
} else if (this.fieldRange < 4000) {
this.fieldRange += 50
m.fieldDrawRadius = this.fieldRange //* Math.min(1, 0.3 + 0.5 * Math.min(1, energy * energy));
drawField()
m.drawCloak()
}
if (tech.isIntangible) {
if (m.isCloak) {

View File

@@ -889,10 +889,7 @@ const powerUps = {
if (document.getElementById("tech-switch")) document.getElementById("tech-switch").innerHTML = ` = <strong>ON</strong>`
m.eyeFillColor = m.fieldMeterColor //'#0cf'
}
if (tech.isRelayEnergy) {
m.setMaxEnergy();
m.energy += 2
}
if (tech.isRelayEnergy) m.setMaxEnergy();
}
},
// giveRandomAmmo() {

View File

@@ -822,7 +822,8 @@ const simulation = {
level.zones = [];
simulation.drawList = [];
if (tech.isDronesTravel && player.alive) {
if (tech.isDronesTravel && m.alive) {
console.log('hi')
//count drones
let count = 0
let deliveryCount = 0
@@ -946,7 +947,7 @@ const simulation = {
}
}
if (m.pos.y > simulation.fallHeight || isNaN(player.position.x)) { // if 4000px deep
if (m.pos.y > simulation.fallHeight) { // if 4000px deep
Matter.Body.setVelocity(player, {
x: 0,
y: 0
@@ -971,6 +972,7 @@ const simulation = {
m.damage(0.1 * simulation.difficultyMode);
m.energy -= 0.1 * simulation.difficultyMode
}
if (isNaN(player.position.x)) m.death();
// if (tech.isEnergyDamage) {
// document.getElementById("tech-capacitor").innerHTML = `(+${(m.energy/0.05).toFixed(0)}%)`

View File

@@ -335,7 +335,7 @@ const spawn = {
let count = 0
function loop() {
if (!simulation.paused) {
if (!simulation.paused && !simulation.onTitlePage) {
count++
if (count < 660) {
if (count === 1) simulation.makeTextLog(`<em>//enter testing mode to set level.levels.length to <strong>Infinite</strong></em>`);
@@ -359,6 +359,7 @@ const spawn = {
document.getElementById("fade-out").style.opacity = 1; //slowly fades out
// build.shareURL(false)
setTimeout(function() {
if (!simulation.onTitlePage) {
simulation.paused = true;
// simulation.clearMap();
// Matter.Composite.clear(composite, keepStatic, [deep = false])
@@ -366,6 +367,7 @@ const spawn = {
engine.world.bodies.forEach((body) => { Matter.Composite.remove(engine.world, body) })
Engine.clear(engine);
simulation.splashReturn();
}
}, 6000);
return
}
@@ -376,7 +378,7 @@ const spawn = {
simulation.makeTextLog(`level.levels.length <span class='color-symbol'>=</span> <strong>Infinite</strong>`);
}, 1500);
} else {
requestAnimationFrame(loop);
if (!simulation.onTitlePage) requestAnimationFrame(loop);
}
}
requestAnimationFrame(loop);

View File

@@ -705,6 +705,34 @@ const tech = {
m.setMovement()
}
},
// {
// name: "coyote",
// description: "",
// maxCount: 1,
// count: 0,
// frequency: 1,
// frequencyDefault: 1,
// allowed() { return true },
// requires: "",
// effect() { // good with melee builds, content skipping builds
// tech.coyoteTime = 120
// // simulation.gravity = function() {
// // function addGravity(bodies, magnitude) {
// // for (var i = 0; i < bodies.length; i++) {
// // bodies[i].force.y += bodies[i].mass * magnitude;
// // }
// // }
// // if (!m.isBodiesAsleep) {
// // addGravity(powerUp, simulation.g);
// // addGravity(body, simulation.g);
// // }
// // player.force.y += player.mass * simulation.g
// // }
// },
// remove() {
// tech.coyoteTime = 5
// }
// },
{
name: "Newton's 1st law",
description: "moving at high <strong>speeds</strong><br>reduces <strong class='color-harm'>harm</strong> by up to <strong>66%</strong>",
@@ -1816,7 +1844,7 @@ const tech = {
},
{
name: "lithium-ion",
description: "if <strong>relay switch</strong> is in the <strong class='color-flop'>ON</strong> state<br>increase your <strong>maximum</strong> <strong class='color-f'>energy</strong> by <strong>200</strong>",
description: "if <strong>relay switch</strong> is in the <strong class='color-flop'>ON</strong> state<br>increase your <strong>maximum</strong> <strong class='color-f'>energy</strong> by <strong>300</strong>",
maxCount: 1,
count: 0,
frequency: 4,
@@ -7510,6 +7538,25 @@ const tech = {
},
remove() {}
},
{
name: "hi",
description: `spawn to seed`,
maxCount: 1,
count: 0,
frequency: 0,
isNonRefundable: true,
isJunk: true,
allowed() {
return true
},
requires: "",
effect() {
document.getElementById("seed").placeholder = Math.initialSeed = String(616)
Math.seed = Math.abs(Math.hash(Math.initialSeed)) //update randomizer seed in case the player changed it
},
remove() {}
},
{
name: "meteor shower",
description: "take a shower, but meteors instead of water",
@@ -7553,7 +7600,7 @@ const tech = {
},
{
name: "Higgs phase transition",
description: "instantly spawn 3 <strong class='color-m'>tech</strong>, but add a chance to<br>remove everything with a 5 minute <strong>half-life</strong>",
description: "instantly spawn 5 <strong class='color-m'>tech</strong>, but add a chance to<br>remove everything with a 5 minute <strong>half-life</strong>",
maxCount: 1,
count: 0,
frequency: 0,
@@ -7566,8 +7613,10 @@ const tech = {
requires: "",
effect() {
powerUps.spawn(m.pos.x, m.pos.y, "tech");
powerUps.spawn(m.pos.x + 20, m.pos.y, "tech");
powerUps.spawn(m.pos.x + 40, m.pos.y, "tech");
powerUps.spawn(m.pos.x + 30, m.pos.y, "tech");
powerUps.spawn(m.pos.x + 60, m.pos.y, "tech");
powerUps.spawn(m.pos.x, m.pos.y - 30, "tech");
powerUps.spawn(m.pos.x + 30, m.pos.y - 60, "tech");
function loop() {
// (1-X)^cycles = chance to be removed //Math.random() < 0.000019 10 min
@@ -9226,8 +9275,8 @@ const tech = {
remove() {}
},
{
name: "Mech v4.48",
description: `open a portal to a primordial version of reality`,
name: "cosmogonic myth",
description: `open a portal to a primordial version of reality<br>after 5 minutes <strong>close</strong> the portal, and spawn 1 of every power up`,
maxCount: 1,
count: 0,
frequency: 0,
@@ -9236,7 +9285,19 @@ const tech = {
allowed() { return true },
requires: "",
effect() {
window.open('https://scratch.mit.edu/projects/14005697/fullscreen/', '_blank')
const urls = ["https://scratch.mit.edu/projects/14005697/fullscreen/", "https://scratch.mit.edu/projects/22573757/fullscreen/", "https://codepen.io/lilgreenland/full/ozXNWZ", "https://codepen.io/lilgreenland/full/wzARJY", "classic/7-1-2017/", "classic/4-15-2018/", "classic/7-11-2019/", "classic/9-8-2019/", "classic/7-15-2020/", "classic/6-1-2021/"]
const choose = urls[Math.floor(Math.random() * urls.length)]
console.log(`opening new tab" ${choose}`)
let tab = window.open(choose, "_blank");
setTimeout(() => {
tab.close();
powerUps.spawn(m.pos.x, m.pos.y, "gun");
setTimeout(() => { powerUps.spawn(m.pos.x, m.pos.y - 50, "ammo") }, 250);
setTimeout(() => { powerUps.spawn(m.pos.x + 50, m.pos.y, "field"); }, 500);
setTimeout(() => { powerUps.spawn(m.pos.x + 50, m.pos.y - 50, "heal"); }, 750);
setTimeout(() => { powerUps.spawn(m.pos.x - 50, m.pos.y, "tech"); }, 1000);
setTimeout(() => { powerUps.spawn(m.pos.x - 50, m.pos.y - 50, "research"); }, 1250);
}, 1000 * 5);
},
remove() {}
},
@@ -9687,4 +9748,5 @@ const tech = {
plasmaDischarge: null,
isFlipFlopHealth: null,
isRelayEnergy: null,
coyoteTime: null
}

View File

@@ -1,18 +1,64 @@
******************************************************** NEXT PATCH **************************************************
added 5 cycles of "coyote time"
this means you can still jump for 5/60 = 0.1 seconds after leaving the ground
let me know if you like the feel
this might cause some unexpected bugs, or reduce the difficulty of some platforming levels
added 2 more classic n-gon dates
JUNK tech: NFT - buy your current game seed
no one is allow to use your seeds
if they use them they are gonna get in trouble
plasma ball
does 10% more damage
moves 20% faster
targets mob bullets better
standing wave has a 45/60->30/60 second cooldown after blocking a shielded mob
but, standing wave now also triggers it's CD on shields that protect groups of mobs
JUNK tech: Mech v4.48 removed
JUNK tech: cosmogonic myth - opens a random classic version of n-gon in a new tab, after 5 minutes close the tab and spawn 1 of every tech
bug fixes
removed the pavilion/ruins map to see if it's causing bugs
******************************************************** TODO ********************************************************
bugs: requirement text man discord messages
bring back:
missiles that fall back and down for a sec after they fire
the old phase decoherence field
make cloak only active on input.field down
could be a tech
would need some other buff
how to make it good enough
combine with not killing tech?
stun mobs that touch you while phased
firing doesn't exit you from cloak
but it does drain some energy
tech pilot wave: Bose Einstein condensate - freeze mobs in superposition with pilot wave
plasma ball
graphics should look more like a real plasma ball
gently scale damage with circleRadius
balance corona discharge
delay on returning to player is annoying
scale float effect with ball size
tech upgrades
greatly improve floating effects while holding
black hole: gives the plasma ball gravity
stun on expansion
plasma orb increases in size and power as it eats enemies
while attached?
make level.do() graphic that only shows direction player is facing
pattern it after cloaking field
will it work with cloaking field at the same time
double jump?
tech coyote time
you can still jump for 2 seconds after falling off a ledge
make it a JUNK tech? so you can keep the name
some other benefit
reduce your gravity also?
increase jump?
tech smoke grenades - mobs inside a cloud can't see player
draw on the region so it's hard for player to see as well
you'd have to make something similar to MACHO that exists after an explosion goes off
@@ -26,18 +72,6 @@ tech mines: mines fire _____ instead of nails
super balls?
foam?
plasma ball
gently scale damage with circleRadius
balance corona discharge
delay on returning to player is annoying
scale float effect with ball size
tech upgrades
greatly improve floating effects while holding
black hole: gives the plasma ball gravity
stun on expansion
plasma orb increases in size and power as it eats enemies
while attached?
tech: frozen mobs die at 10% life
tech: harpoons stick into enemies
@@ -703,6 +737,7 @@ possible names for tech
particle accelerator
superluminal signalling
NP-complete
lenticular lens: is an array of lenses, designed so that when viewed from slightly different angles, different parts of the image underneath are shown.
a tutorial / lore intro
needs to be optional so it doesn't slow experienced players