diff --git a/js/bullet.js b/js/bullet.js index 139edba..8d04cbc 100644 --- a/js/bullet.js +++ b/js/bullet.js @@ -280,7 +280,9 @@ const b = { }, fireCDscale: 1, setFireCD() { + b.fireCDscale = tech.fireRate * tech.slowFire * tech.researchHaste * tech.aimDamage + if (m.fieldMode === 6) b.fireCDscale *= 0.75 if (tech.isFastTime) b.fireCDscale *= 0.5 if (tech.isFireRateForGuns) b.fireCDscale *= Math.pow(0.82, b.inventory.length) if (tech.isFireMoveLock) b.fireCDscale *= 0.55 diff --git a/js/level.js b/js/level.js index 02a5c03..6672ef0 100644 --- a/js/level.js +++ b/js/level.js @@ -23,16 +23,17 @@ const level = { // powerUps.research.changeRerolls(100000) // m.immuneCycle = Infinity //you can't take damage // tech.tech[297].frequency = 100 - // m.setField("standing wave") //molecular assembler standing wave time dilation perfect diamagnetism metamaterial cloaking wormhole negative mass + // m.setField("metamaterial cloaking") //molecular assembler standing wave time dilation perfect diamagnetism metamaterial cloaking wormhole negative mass // b.giveGuns("laser") //0 nail gun 1 shotgun 2 super balls 3 matter wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser // b.guns[0].ammo = 1000000 - // tech.giveTech("expansion") + // tech.giveTech("1st ionization energy") // for (let i = 0; i < 1; ++i) tech.giveTech("field coupling") // for (let i = 0; i < 1; ++i) tech.giveTech("free-electron laser") // m.damage(0.1); // for (let i = 0; i < 1; i++) tech.giveTech("dynamic equilibrium") // for (let i = 0; i < 10; i++) powerUps.directSpawn(450, -50, "tech"); - // for (let i = 0; i < 10; i++) powerUps.directSpawn(450, -50, "research"); + // for (let i = 0; i < 10; i++) powerUps.directSpawn(1750, -500, "boost"); + // for (let i = 0; i < 10; i++) powerUps.directSpawn(1750, -500, "coupling"); // spawn.starter(1900, -500, 200) // spawn.beetleBoss(1900, -400) diff --git a/js/player.js b/js/player.js index a9d1d8d..7db4cb1 100644 --- a/js/player.js +++ b/js/player.js @@ -874,6 +874,7 @@ const m = { ctx.restore(); m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal + powerUps.boost.draw() }, drawDefault() { ctx.fillStyle = m.fillColor; @@ -896,6 +897,7 @@ const m = { ctx.stroke(); ctx.restore(); m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal + powerUps.boost.draw() }, // ********************************************* // **************** fields ********************* @@ -1373,11 +1375,23 @@ const m = { m.fieldCDcycle = m.cycle + m.fieldBlockCD; if (!who.isInvulnerable && (m.coupling && m.fieldMode < 3) && bullet.length < 250) { //for standing wave mostly for (let i = 0; i < m.coupling; i++) { - const sub = Vector.mult(Vector.normalise(Vector.sub(who.position, m.pos)), (m.fieldRange * m.harmonicRadius) * (0.4 + 0.3 * Math.random())) //m.harmonicRadius should be 1 unless you are standing wave expansion - const rad = Vector.rotate(sub, 1 * (Math.random() - 0.5)) - const angle = Math.atan2(sub.y, sub.x) - b.iceIX(6 + 6 * Math.random(), angle + 3 * (Math.random() - 0.5), Vector.add(m.pos, rad)) + if (m.coupling - i > Math.random()) { + const sub = Vector.mult(Vector.normalise(Vector.sub(who.position, m.pos)), (m.fieldRange * m.harmonicRadius) * (0.4 + 0.3 * Math.random())) //m.harmonicRadius should be 1 unless you are standing wave expansion + const rad = Vector.rotate(sub, 1 * (Math.random() - 0.5)) + const angle = Math.atan2(sub.y, sub.x) + b.iceIX(6 + 6 * Math.random(), angle + 3 * (Math.random() - 0.5), Vector.add(m.pos, rad)) + } } + + // let count = 0 + // for(let j=0; j<100;j++){ + // const len = m.coupling + 0.5 * (Math.random() - 0.5) + // for (let i = 0; i < len; i++) { + // count++ + // } + // } + // console.log(count) + } const unit = Vector.normalise(Vector.sub(player.position, who.position)) if (tech.blockDmg) { @@ -1562,7 +1576,7 @@ const m = { return `deflecting condenses +${Math.ceil(couple)} ice IX` // return `invulnerable +${2*couple} seconds post collision` case 3: //negative mass - return `+${27*couple}% defense` + return `+${((1-0.73 ** couple)*100).toFixed(1)}% defense` case 4: //assembler return `generate ${6*couple} energy per second` case 5: //plasma @@ -1582,8 +1596,8 @@ const m = { // m.setMaxHealth(); m.setFieldRegen() mobs.setMobSpawnHealth(); - if ((m.fieldMode === 0 || m.fieldMode === 9) && !build.isExperimentSelection && !simulation.isTextLogOpen) simulation.circleFlare(0.4); powerUps.setDupChance(); + if ((m.fieldMode === 0 || m.fieldMode === 9) && !build.isExperimentSelection && !simulation.isTextLogOpen) simulation.circleFlare(0.4); // m.collisionImmuneCycles = 30 + m.coupling * 120 //2 seconds // switch (m.fieldMode) { // case 0: //field emitter @@ -1757,7 +1771,7 @@ const m = { m.harmonicRadius = 0.994 * m.harmonicRadius + 0.006 } } - m.harmonicShield() + if (!simulation.isTimeSkipping) m.harmonicShield() } m.drawRegenEnergy() } @@ -1790,11 +1804,13 @@ const m = { mob[i].locatePlayer(); const unit = Vector.normalise(Vector.sub(m.fieldPosition, mob[i].position)) m.fieldCDcycle = m.cycle + m.fieldBlockCD + (mob[i].isShielded ? 15 : 0); - if (bullet.length < 250) { + if (!mob[i].isInvulnerable && bullet.length < 250) { for (let i = 0; i < m.coupling; i++) { - const angle = m.fieldAngle + 4 * m.fieldArc * (Math.random() - 0.5) - const radius = m.fieldRange * (0.6 + 0.3 * Math.random()) - b.iceIX(6 + 6 * Math.random(), angle, Vector.add(m.fieldPosition, { x: radius * Math.cos(angle), y: radius * Math.sin(angle) })) + if (m.coupling - i > Math.random()) { + const angle = m.fieldAngle + 4 * m.fieldArc * (Math.random() - 0.5) + const radius = m.fieldRange * (0.6 + 0.3 * Math.random()) + b.iceIX(6 + 6 * Math.random(), angle, Vector.add(m.fieldPosition, { x: radius * Math.cos(angle), y: radius * Math.sin(angle) })) + } } } if (tech.blockDmg) { //electricity diff --git a/js/powerup.js b/js/powerup.js index 418192d..57e32d9 100644 --- a/js/powerup.js +++ b/js/powerup.js @@ -114,7 +114,37 @@ const powerUps = { }, tech(num = 1) { return `
` - } + }, + coupling(num = 1) { + switch (num) { + case 1: + return `
` + } + let text = '' + for (let i = 0; i < num; i++) { + text += `
` + } + text += '
    ' + for (let i = 0; i < num; i++) { + text += '  ' + } + return text + }, + boost(num = 1) { + switch (num) { + case 1: + return `
` + } + let text = '' + for (let i = 0; i < num; i++) { + text += `
` + } + text += '
    ' + for (let i = 0; i < num; i++) { + text += '  ' + } + return text + }, }, totalPowerUps: 0, //used for tech that count power ups at the end of a level do() {}, @@ -303,7 +333,7 @@ const powerUps = { }, endDraft(type, isCanceled = false) { //type should be a gun, tech, or field if (isCanceled) { - if (tech.isCancelTech && Math.random() < 0.94) { + if (tech.isCancelTech && Math.random() < 0.9) { // powerUps.research.use('tech') powerUps[type].effect(); return @@ -326,6 +356,7 @@ const powerUps = { } } if (tech.isCancelCouple) { + simulation.makeTextLog(`m.coupling += 0.5`); m.coupling += 0.5 m.couplingChange() } @@ -364,6 +395,42 @@ const powerUps = { if (m.immuneCycle < m.cycle + 15) m.immuneCycle = m.cycle + 15; //player is immune to damage for 30 cycles if (m.holdingTarget) m.drop(); }, + coupling: { + name: "coupling", + color: "#0ae", //"#0cf", + size() { + return 13; + }, + effect() { + simulation.makeTextLog(`m.coupling += 0.1`); + m.coupling += 0.1 + m.couplingChange() + }, + }, + boost: { + name: "boost", + color: "#f55", //"#0cf", + size() { + return 11; + }, + endCycle: 0, + duration: 600, + damage: 1.5, + effect() { + powerUps.boost.endCycle = m.cycle + Math.floor(Math.max(0, powerUps.boost.endCycle - m.cycle) * 0.6) + powerUps.boost.duration //duration+seconds plus 2/3 of current time left + }, + draw() { + // console.log(this.endCycle) + if (powerUps.boost.endCycle > m.cycle) { + ctx.strokeStyle = "rgba(255,0,0,0.8)" //m.fieldMeterColor; //"rgba(255,255,0,0.2)" //ctx.strokeStyle = `rgba(0,0,255,${0.5+0.5*Math.random()})` + ctx.beginPath(); + const arc = (powerUps.boost.endCycle - m.cycle) / powerUps.boost.duration + ctx.arc(m.pos.x, m.pos.y, 28, m.angle - Math.PI * arc, m.angle + Math.PI * arc); //- Math.PI / 2 + ctx.lineWidth = 4 + ctx.stroke(); + } + } + }, research: { count: 0, name: "research", @@ -1203,6 +1270,12 @@ const powerUps = { powerUps.spawn(x, y, "field"); return; } + if (tech.isCouplingPowerUps && Math.random() < 0.17) { + powerUps.spawn(x, y, "coupling"); + } + if (tech.isBoostPowerUps && Math.random() < 0.17) { + powerUps.spawn(x, y, "boost"); + } // if (Math.random() < 0.01) { // powerUps.spawn(x, y, "research"); // return; @@ -1389,6 +1462,7 @@ const powerUps = { !(tech.isEnergyNoAmmo && target === 'ammo') && (!simulation.isNoPowerUps) ) { + if (tech.isBoostReplaceAmmo && target === 'ammo') target = 'boost' powerUps.directSpawn(x, y, target, moving, mode, size) if (Math.random() < tech.duplicationChance()) { powerUps.directSpawn(x, y, target, moving, mode, size) diff --git a/js/tech.js b/js/tech.js index e860cb8..b88ea79 100644 --- a/js/tech.js +++ b/js/tech.js @@ -209,6 +209,7 @@ const tech = { damage: 1, //used for tech changes to player damage that don't have complex conditions damageFromTech() { let dmg = tech.damage //m.fieldDamage + if (powerUps.boost.endCycle > m.cycle) dmg *= 1 + powerUps.boost.damage if (m.coupling && (m.fieldMode === 0 || m.fieldMode === 5)) dmg *= 1 + 0.15 * m.coupling if (m.isSneakAttack && m.sneakAttackCycle + Math.min(120, 0.5 * (m.cycle - m.enterCloakCycle)) > m.cycle) dmg *= 4.33 * (1 + 0.33 * m.coupling) if (tech.deathSkipTime) dmg *= 1 + 0.6 * tech.deathSkipTime @@ -526,7 +527,7 @@ const tech = { allowed() { return !tech.isEnergyNoAmmo }, - requires: "not exciton", + requires: "not non-renewables", effect() { tech.isAmmoForGun = true; }, @@ -548,7 +549,7 @@ const tech = { allowed() { return !tech.isEnergyNoAmmo }, - requires: "not exciton", + requires: "not non-renewables", effect() { tech.ammoCap = 16; powerUps.ammo.effect() @@ -567,7 +568,7 @@ const tech = { allowed() { return !tech.isEnergyNoAmmo }, - requires: "not exciton", + requires: "not non-renewables", effect() { tech.isAmmoFromHealth = true; }, @@ -576,7 +577,7 @@ const tech = { } }, { - name: "exciton", + name: "non-renewables", description: `+88% damage
${powerUps.orb.ammo()} can't spawn`, maxCount: 1, count: 0, @@ -1738,26 +1739,26 @@ const tech = { tech.isBlockPowerUps = false } }, - // { - // name: "Pauli exclusion", - // description: `after mob collisions
become invulnerable for +3 seconds`, - // maxCount: 9, - // count: 0, - // frequency: 1, - // frequencyDefault: 1, - // allowed() { return true }, - // requires: "", - // effect() { - // m.collisionImmuneCycles += 180; - // if (m.immuneCycle < m.cycle + m.collisionImmuneCycles) m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage - // }, - // remove() { - // m.collisionImmuneCycles = 30; - // } - // }, + { + name: "Pauli exclusion", + description: `after mob collisions
become invulnerable for +3 seconds`, + maxCount: 9, + count: 0, + frequency: 1, + frequencyDefault: 1, + allowed() { return true }, + requires: "", + effect() { + m.collisionImmuneCycles += 180; + if (m.immuneCycle < m.cycle + m.collisionImmuneCycles) m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage + }, + remove() { + m.collisionImmuneCycles = 30; + } + }, { name: "spin–statistics theorem", - description: `every 7 seconds
become invulnerable for +1.75 seconds`, + description: `every 7 seconds
become invulnerable for +1.8 seconds`, maxCount: 3, count: 0, frequency: 1, @@ -1767,7 +1768,7 @@ const tech = { }, requires: "", effect() { - tech.cyclicImmunity += 105; + tech.cyclicImmunity += 108; }, remove() { tech.cyclicImmunity = 0; @@ -2226,7 +2227,7 @@ const tech = { name: "1st ionization energy", link: `1st ionization energy`, description: `after you collect ${powerUps.orb.heal()}
+10 maximum energy`, - description: `convert ${powerUps.orb.heal()} into

give +10 maximum energy`, + description: `convert ${powerUps.orb.heal()} into

give +10 maximum energy`, maxCount: 1, count: 0, frequency: 2, @@ -2237,7 +2238,7 @@ const tech = { requires: "mass-energy equivalence", effect() { tech.healGiveMaxEnergy = true; //tech.healMaxEnergyBonus given from heal power up - powerUps.heal.color = "#0ae" + powerUps.heal.color = "#ff0" //"#0ae" for (let i = 0; i < powerUp.length; i++) { //find active heal power ups and adjust color live if (powerUp[i].name === "heal") powerUp[i].color = powerUps.heal.color } @@ -3293,6 +3294,26 @@ const tech = { } } }, + { + name: "exciton", + descriptionFunction() { + return `after mobs die they have a 17% chance to
spawn ${powerUps.orb.boost(1)} that give +${powerUps.boost.damage*100}% damage for ${(powerUps.boost.duration/60).toFixed(0)} seconds
` + }, + maxCount: 1, + count: 0, + frequency: 1, + frequencyDefault: 1, + allowed() { + return true + }, + requires: "", + effect() { + tech.isBoostPowerUps = true + }, + remove() { + tech.isBoostPowerUps = false + } + }, { name: "eternalism", description: "+34% damage
time can't be paused (time can be dilated)", @@ -3316,7 +3337,7 @@ const tech = { }, { name: "paradigm shift", - description: `clicking tech while paused ejects them
16% chance to fail`, + description: `clicking tech while paused ejects them
16% chance to remove without ejecting`, maxCount: 1, count: 0, frequency: 1, @@ -3372,7 +3393,8 @@ const tech = { }, requires: "", effect() { - m.coupling++ + simulation.makeTextLog(`m.coupling += 1`); + m.coupling += 1 m.couplingChange() }, remove() { @@ -3383,12 +3405,12 @@ const tech = { { name: "quintessence", descriptionFunction() { - return `use all your ${powerUps.orb.research(1)} to get +${powerUps.research.count*this.couplingToResearch} coupling
${ m.couplingDescription()} ${m.fieldMode === 0 ? "" : "per coupling"}` + return `use all your ${powerUps.orb.research(1)} to get +${this.count ? this.researchUsed*this.couplingToResearch:powerUps.research.count*this.couplingToResearch} coupling
${ m.couplingDescription()} ${m.fieldMode === 0 ? "" : "per coupling"}` }, maxCount: 1, count: 0, frequency: 1, - frequencyDefault: 1, + frequencyDefault: 100, allowed() { return powerUps.research.count > 3 }, @@ -3399,6 +3421,7 @@ const tech = { while (powerUps.research.count > 0) { powerUps.research.changeRerolls(-1) this.researchUsed++ + simulation.makeTextLog(`m.coupling += ${(this.couplingToResearch).toFixed(2)}`); m.coupling += this.couplingToResearch } m.couplingChange() @@ -3412,6 +3435,26 @@ const tech = { m.couplingChange() } }, + { + name: "virtual particles", + descriptionFunction() { + return `after mobs die they have a 17% chance to
spawn ${powerUps.orb.coupling(1)} that give +0.1 coupling` + }, + maxCount: 1, + count: 0, + frequency: 1, + frequencyDefault: 1, + allowed() { + return true + }, + requires: "", + effect() { + tech.isCouplingPowerUps = true //about 20-30 mobs per level so at 16% and 0.1 coupling that's about 25 * 0.16 * 0.1 = 0.4 coupling per level with out duplication + }, + remove() { + tech.isCouplingPowerUps = false + } + }, { name: "fine-structure constant", descriptionFunction() { @@ -3428,6 +3471,7 @@ const tech = { requires: "", effect() { tech.isCouplingNoHit = true + simulation.makeTextLog(`m.coupling += ${(this.value).toFixed(1)}`); m.coupling += this.value m.couplingChange() }, @@ -3462,7 +3506,7 @@ const tech = { { name: "options exchange", link: `options exchange`, - description: `clicking × for a field, tech, or gun has a 94%
chance to randomize choices and not cancel`, + description: `clicking × for a field, tech, or gun has a 90%
chance to randomize choices and not cancel`, maxCount: 1, count: 0, frequency: 1, @@ -5849,7 +5893,7 @@ const tech = { allowed() { return tech.haveGunCheck("foam") && !tech.isEnergyNoAmmo }, - requires: "foam, not exciton", + requires: "foam, not non-renewables", ammoLost: 0, effect() { b.guns[8].ammoPack = b.guns[8].ammoPack * 12; @@ -6197,6 +6241,27 @@ const tech = { tech.isStuckOn = false } }, + { + name: "quasiparticles", + descriptionFunction() { + return `replace all ${powerUps.orb.ammo(1)} spawns with ${powerUps.orb.boost(1)} which give
+${powerUps.boost.damage*100}% damage for ${(powerUps.boost.duration/60).toFixed(0)} seconds` + }, + isGunTech: true, + maxCount: 1, + count: 0, + frequency: 2, + frequencyDefault: 2, + allowed() { + return tech.haveGunCheck("laser") + }, + requires: "laser, not pulse", + effect() { + tech.isBoostReplaceAmmo = true + }, + remove() { + tech.isBoostReplaceAmmo = false + } + }, { name: "relativistic momentum", description: "lasers push mobs and blocks", @@ -7325,7 +7390,7 @@ const tech = { }, { name: "time crystals", - description: "+300% passive energy generation", + description: "+200% passive energy generation", isFieldTech: true, maxCount: 1, count: 0, @@ -7567,7 +7632,7 @@ const tech = { } }, { - name: "virtual particles", + name: "vacuum fluctuation", description: `use ${powerUps.orb.research(6)}to exploit your field for a
+11% chance to duplicate spawned power ups`, isFieldTech: true, maxCount: 1, @@ -10625,5 +10690,8 @@ const tech = { isLastHitDamage: null, isCloakHealLastHit: null, isRicochet: null, - isCancelCouple: null + isCancelCouple: null, + isCouplingPowerUps: null, + isBoostPowerUps: null, + isBoostReplaceAmmo: null } \ No newline at end of file diff --git a/style.css b/style.css index 612736f..99f6c0c 100644 --- a/style.css +++ b/style.css @@ -193,7 +193,7 @@ summary { border-radius: 8px; z-index: 12; background-color: #444; - grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); + grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); grid-auto-rows: minmax(auto, auto); font-size: 1.3em; /* box-shadow: 0px 0px 40px 20px rgba(255, 255, 255, 0.25); */ @@ -236,7 +236,7 @@ summary { margin: 0px; display: none; - grid-template-columns: 325px; + grid-template-columns: 345px; /* grid-template-columns: repeat(auto-fit, minmax(310px, 1fr)); */ grid-auto-rows: minmax(auto, auto); grid-gap: 0px; @@ -278,7 +278,7 @@ summary { background-color: var(--build-bg-color); display: none; - grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); + grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); grid-auto-flow: row; grid-auto-rows: minmax(auto, auto); grid-gap: 0px; @@ -800,7 +800,7 @@ summary { background-color: #467; border: 0.5px #fff solid; opacity: 0.95; - margin-bottom: -2px; + margin-bottom: -1.5px; } .heal-circle { @@ -814,6 +814,26 @@ summary { margin-bottom: -3px; } +.coupling-circle { + width: 10px; + height: 10px; + border-radius: 50%; + display: inline-block; + background-color: #0ae; + border: 0.5px #fff solid; + margin-bottom: -0.5px; +} +.boost-circle { + width: 10px; + height: 10px; + border-radius: 50%; + display: inline-block; + background-color: #f03; + border: 0.5px #fff solid; + opacity: 0.9; + margin-bottom: -0.5px; +} + .circle-grid-shadow { width: 43px; height: 43px; @@ -929,6 +949,7 @@ summary { /* animation: vibrate 500ms linear infinite alternate; display: inline-block; */ /* text-shadow: 0px 0px 2px #0cf; */ + /* text-shadow: 0px 0px 1.5px #0cf; */ text-shadow: 0px 0px 1.5px #0cf; /* color: hsl(255, 82%, 59%); */ letter-spacing: 1px; diff --git a/todo.txt b/todo.txt index 18904cb..bd5c991 100644 --- a/todo.txt +++ b/todo.txt @@ -1,30 +1,33 @@ ******************************************************** NEXT PATCH ************************************************** -coupling - crystallography renamed quintessence - wormhole -> energy after eating blocks - penrose process is removed - perfect diamagnatism and standing wave -> ice IX after blocking - tech triple point removed - plasma torch -> +damage +tech: virtual particles - mobs have a chance to spawn coupling power ups + old tech virtual particles renamed vacuum fluctuation -killing one of the first 3->4 snake body mobs makes snake bosses vulnerable -shooterBoss shoots 3-6 smaller bullets +tech: exciton - mobs have a chance to spawn a boost + boosts are a power up that increases your damage for 10 seconds + old tech exciton renamed non-renewables +laser tech: quasiparticles - replace all ammo with boosts +added +20px to grid elements to prevent text spillover bug fixes + *********************************************************** TODO ***************************************************** coupling + pause menu +defense on coupling description goes above 100% + put coupling description as 4th line on field description + raw text no function call + no need for coupling description in power ups, pause negative coupling? - + wouldn't work for iceIX coupling tech - names: strongly coupled, Vibronic coupling, Residual dipolar coupling, NMR coupling, quintessence + names: strongly coupled, Vibronic coupling, NMR coupling tech: +x% field coupling, your field changes randomly every y seconds tech: coupling starts at 200%, but decays when the field is in use, coupling recharges when the field is not in use some fields aren't used much (that's ok?) -triple point iceIX needs to spawn in the radius of the field and an arc in the same quadrant as the mob +tech: increase the effect of boosts, but shorten the duration? tech give laser mines more lasers (3->4? 5?) @@ -41,8 +44,6 @@ make orbitals increase orbital rotation speed after Orbital boss takes damage worms can target player, buff their damage can't target player in first few seconds? -draw player transparent or opaque when cloaking field is on - plasma field tech - similar to regression, but for plasma ticks greatly increase walking speed @@ -87,7 +88,6 @@ tech expansion: field coupling also expands each fields in different ways tech: missiles explode a 2nd time after 1/2 a second (with a slightly different position determined by original velocity) -1st ionisation energy should scale with heath powerup efficiency The tech that makes blocks that fall into a wormhole give energy should scale with block size, with the same formula as tokomak junk suggestion: useless machine - ejects itself and removes itself from the item pool