animated level load

animated new level load graphics for reactor and final level
autoZoom code rewritten to work with pause better using the ephemera system
  this might cause bugs, I already found a few
intro level renamed initial
extra ammo power ups on why difficulty for final and reactor levels
removed falling off the map damage on levels that still had falling off damage

mob: stinger - has speed that adjusts as it flaps it's wings and a short range laser
tech: strange loop - +9% damage, removing it gives null hypothesis and strange attractor
tech: martingale - +11% damage, removing this has a 50% chance to not remove and to double it's damage

paradigm shift removes 6 health when it ejects a tech, but now has a 85->97% chance to work
ammo, heal, research tech spawn extra power ups after each time you take them
tungsten carbide skin has a hexagon look and  +222->300 max health
Bayesian statistics spawn 3->6 research
ansatz spawns 2->3 research if you have no research
Ψ(t) collapse 16->21 research
futures exchange 4.3->4.7% duplication
replication 9->10 duplication
stimulated emission 17->19% duplication
anthropic principle spawn 5->16 heals when you die
supply chain: no long gives JUNK instead triples the frequency of finding applied science
electronegativity 0.22->0.26% damage per energy
non-renewables 88->97% damage
anticorrelation 100->111% damage
decorrelation 70->77% defense
parasitism 83->93% damage
torpor 66->74% defense

bug fix:
  recycling works with mass-energy (although it doesn't do much)
  ternary wasn't working in many situations, but it should now
  fixed bubble fusion exploit that triggers on mobs in factory endlessly
  bot fabrication was making 1 extra bot and giving negative research sometimes
This commit is contained in:
landgreen
2024-01-21 12:57:11 -08:00
parent c47d86064b
commit 4e6acdd5d0
14 changed files with 928 additions and 340 deletions

View File

@@ -1409,14 +1409,16 @@ window.addEventListener("keydown", function (event) {
if (event.key === "X") m.death(); //only uppercase
switch (event.key.toLowerCase()) {
case "o":
simulation.isAutoZoom = false;
simulation.zoomScale /= 0.9;
simulation.setZoom();
// simulation.isAutoZoom = false;
// simulation.zoomScale /= 0.9;
// simulation.setZoom();
simulation.zoomTransition(simulation.zoomScale / 0.9)
break;
case "i":
simulation.isAutoZoom = false;
simulation.zoomScale *= 0.9;
simulation.setZoom();
// simulation.isAutoZoom = false;
// simulation.zoomScale *= 0.9;
// simulation.setZoom();
simulation.zoomTransition(simulation.zoomScale * 0.9)
break
case "`":
powerUps.directSpawn(simulation.mouseInGame.x, simulation.mouseInGame.y, "research");

View File

@@ -9,7 +9,7 @@ const level = {
onLevel: -1,
levelsCleared: 0,
// playableLevels: ["pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion"],
//see level.populateLevels: (intro, ... , reservoir or factory, reactor, ... , subway, final) added later
//see level.populateLevels: (initial, ... , reservoir or factory, reactor, ... , subway, final) added later
playableLevels: ["labs", "rooftops", "skyscrapers", "warehouse", "highrise", "office", "aerie", "satellite", "sewers", "testChamber", "pavilion", "lock"],
communityLevels: ["gauntlet", "stronghold", "basement", "crossfire", "vats", "run", "ngon", "house", "perplex", "coliseum", "tunnel", "islands", "temple", "dripp", "biohazard", "stereoMadness", "yingYang", "staircase", "fortress", "commandeer", "clock", "buttonbutton", "downpour", "superNgonBros", "underpass", "cantilever", "tlinat", "ruins", "ace", "crimsonTowers", "LaunchSite", "shipwreck", "unchartedCave", "dojo"],
trainingLevels: ["walk", "crouch", "jump", "hold", "throw", "throwAt", "deflect", "heal", "fire", "nailGun", "shotGun", "superBall", "matterWave", "missile", "stack", "mine", "grenades", "harpoon", "diamagnetism"],
@@ -36,22 +36,24 @@ const level = {
// b.giveGuns("harpoon") //0 nail gun 1 shotgun 2 super balls 3 wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser
// b.guns[8].ammo = 100000000
// requestAnimationFrame(() => { tech.giveTech("Higgs mechanism") });
// for (let i = 0; i < 1; ++i) tech.giveTech("Higgs mechanism")
// for (let i = 0; i < 1; ++i) tech.giveTech("topological defect")
// for (let i = 0; i < 1; ++i) tech.giveTech("Hilbert space")
// for (let i = 0; i < 1; ++i) tech.giveTech("martingale")
// for (let i = 0; i < 1; ++i) tech.giveTech("paradigm shift")
// for (let i = 0; i < 1; ++i) tech.giveTech("bubble fusion")
// requestAnimationFrame(() => { for (let i = 0; i < 10; i++) tech.giveTech("orbital-bot") });
// requestAnimationFrame(() => { for (let i = 0; i < 10; i++) b.orbitBot(m.pos, false) });
// m.skin.hexagon();
// for (let i = 0; i < 1; i++) tech.giveTech("cascading failure")
// for (let i = 0; i < 1; i++) tech.giveTech("tungsten carbide")
// for (let i = 0; i < 1; ++i) tech.giveTech("induction furnace")
// for (let i = 0; i < 1; ++i) tech.giveTech("autonomous defense")
// for (let i = 0; i < 3; i++) powerUps.directSpawn(450, -50, "tech");
// for (let i = 0; i < 10; i++) powerUps.directSpawn(1750, -500, "research");
// for (let i = 0; i < 100; i++) powerUps.directSpawn(1750, -500, "coupling");
// level.skyscrapers();
// level.testing();
// for (let i = 0; i < 4; ++i) spawn.hopMother(1900, -500)
// for (let i = 0; i < 10; ++i) spawn.starter(1900, -500, 50)
// for (let i = 0; i < 4; ++i) spawn.stinger(1900, -500)
// for (let i = 0; i < 1; ++i) spawn.timeSkipBoss(1900, -2500)
// spawn.beetleBoss(1900, -500, 25)
// spawn.slasher2(2000, -1150)
@@ -62,7 +64,7 @@ const level = {
// spawn.tetherBoss(1900, -500, { x: 1900, y: -500 })
// for (let i = 0; i < 40; ++i) tech.giveTech()
level[simulation.isTraining ? "walk" : "intro"]() //normal starting level **************************************************
level[simulation.isTraining ? "walk" : "initial"]() //normal starting level **************************************************
// spawn.bodyRect(2425, -120, 200, 200);
// console.log(body[body.length - 1].mass)
@@ -74,9 +76,9 @@ const level = {
// for (let i = 0; i < 20; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "ammo");
// for (let i = 0; i < 2; i++) powerUps.spawn(player.position.x + Math.random() * 50, player.position.y - Math.random() * 50, "field", false);
//lore testing
// simulation.isCheating = false //true;
// for (let i = 0; i < 5; i++) tech.giveTech("undefined")
// lore.techCount = 2
// simulation.isCheating = false //true;
// level.levelsCleared = 10
// localSettings.loreCount = 5 //this sets what conversation is heard
// if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
@@ -284,6 +286,150 @@ const level = {
tech.isDeathAvoidedThisLevel = false;
simulation.updateTechHUD();
simulation.clearNow = true; //triggers in simulation.clearMap to remove all physics bodies and setup for new map
//pop up new level info screen for a few seconds
if (!simulation.isChoosing && m.alive && (level.levels[level.onLevel] === "final" || level.levels[level.onLevel] === "reactor")) { //level.levels[level.onLevel] === "subway" ||
//pause
if (!simulation.paused) {
simulation.paused = true;
simulation.isChoosing = true; //stops p from un pausing on key down
// build.pauseGrid()
// document.body.style.cursor = "auto";
}
//build level info
document.getElementById("choose-grid").style.gridTemplateColumns = "250px"
let text = `<div><div class="card-background" style="height:auto; border: none; background-color: transparent; line-height: 160%; background-color: var(--card-color); font-size: 1.15em;"> <div class="card-text">`
for (let i = 0; i < level.levels.length; i++) {
if (i < level.levelsCleared) {
text += `<div style="user-select: none;">${level.levels[i]}</div>`
} else if (i === level.levelsCleared) {
// text += `<div><strong class="fade-in-faster">${level.levels[i]}</strong></div>`
text += `<div class="unblur" style="user-select: none;"><strong>${level.levels[i]}</strong></div>`
} else {
text += `<div class= "blurry-text" style="user-select: none;">${level.levels[i]}</div>` //blurry text
// ???????? text
// text += `<div style="user-select: none; color: #bbb;">`
// for (let j = 0; j < level.levels[i].length; j++) text += `?`
// text += `</div>`
}
}
text += `</div> </div></div>`
document.getElementById("choose-grid").innerHTML = text
//show level info
document.getElementById("choose-grid").style.opacity = "1"
document.getElementById("choose-grid").style.transitionDuration = "0.25s"; //how long is the fade in on
document.getElementById("choose-grid").style.visibility = "visible"
simulation.draw.cons();
simulation.draw.body();
level.customTopLayer();
let count = simulation.testing ? 0 : 240
let newLevelDraw = () => {
count--
if (count > 0) {
requestAnimationFrame(newLevelDraw);
} else { //unpause
// document.body.style.cursor = "none";
if (m.immuneCycle < m.cycle + 15) m.immuneCycle = m.cycle + 30; //player is immune to damage for 30 cycles
if (simulation.paused) requestAnimationFrame(cycle);
if (m.alive) simulation.paused = false;
simulation.isChoosing = false; //stops p from un pausing on key down
build.unPauseGrid()
document.getElementById("choose-grid").style.opacity = "0"
setTimeout(() => {
document.getElementById("choose-grid").style.visibility = "hidden"
}, 1000);
}
//draw
simulation.wipe();
m.look();
simulation.camera();
// if (count < 30) {
// }
// if (count < 60) {
// simulation.draw.cons();
// simulation.draw.body();
// level.customTopLayer();
// simulation.draw.body();
// simulation.draw.drawMapPath();
// mobs.draw();
// } else
// if (count < 240) {
simulation.draw.wireFrame();
// }
// else if (count === 91) { //hide text boss
// document.getElementById("choose-grid").style.opacity = "0"
// setTimeout(() => {
// document.getElementById("choose-grid").style.visibility = "hidden"
// }, 1000);
// }
ctx.restore();
simulation.drawCursor();
}
requestAnimationFrame(newLevelDraw);
// // clear
// requestAnimationFrame(() => {
// simulation.wipe();
// });
// //wireframe
// setTimeout(() => {
// requestAnimationFrame(() => {
// simulation.wipe();
// simulation.camera();
// simulation.draw.wireFrame();
// ctx.restore();
// });
// }, 500);
// //almost normal draw
// setTimeout(() => {
// requestAnimationFrame(() => {
// simulation.wipe();
// simulation.camera();
// // ctx.fillStyle = "rgba(0,0,0,0.66)"
// // ctx.fill(simulation.draw.mapPath);
// simulation.draw.drawMapPath();
// ctx.restore();
// });
// }, 1000);
// //normal draw
// setTimeout(() => {
// requestAnimationFrame(() => {
// simulation.wipe();
// simulation.camera();
// // level.custom();
// simulation.draw.cons();
// simulation.draw.body();
// // m.draw();
// // m.hold();
// level.customTopLayer();
// simulation.draw.drawMapPath();
// ctx.restore();
// });
// }, 1500);
// //unpause
// setTimeout(() => {
// document.body.style.cursor = "none";
// if (m.immuneCycle < m.cycle + 15) m.immuneCycle = m.cycle + 15; //player is immune to damage for 30 cycles
// if (simulation.paused) requestAnimationFrame(cycle);
// if (m.alive) simulation.paused = false;
// simulation.isChoosing = false; //stops p from un pausing on key down
// build.unPauseGrid()
// document.getElementById("choose-grid").style.opacity = "0"
// // document.getElementById("choose-grid").style.visibility = "hidden"
// setTimeout(() => {
// document.getElementById("choose-grid").style.visibility = "hidden"
// }, 1000);
// }, 2000);
}
}
},
populateLevels() { //run a second time if URL is loaded
@@ -335,7 +481,7 @@ const level = {
level.levels.splice(Math.floor(Math.seededRandom(level.levels.length * 0.6, level.levels.length)), 0, Math.random() < 0.5 ? "factory" : "reservoir"); //add level to the back half of the randomized levels list
level.levels.splice(Math.floor(Math.seededRandom(level.levels.length * 0.6, level.levels.length)), 0, "reactor"); //add level to the back half of the randomized levels list
if (!build.isExperimentSelection || (build.hasExperimentalMode && !simulation.isCheating)) { //experimental mode is endless, unless you only have an experiment Tech
level.levels.unshift("intro"); //add level to the start of the randomized levels list
level.levels.unshift("initial"); //add level to the start of the randomized levels list
level.levels.push("subway"); //add level to the end of the randomized levels list
level.levels.push("final"); //add level to the end of the randomized levels list
}
@@ -1911,7 +2057,7 @@ const level = {
powerUps.addResearchToLevel() //needs to run after mobs are spawned
},
testing() {
simulation.enableConstructMode() //tech.giveTech('motion sickness') //used to build maps in testing mode
// simulation.enableConstructMode() //tech.giveTech('motion sickness') //used to build maps in testing mode
document.body.style.backgroundColor = "#fff";
// color.map = "#444" //custom map color
@@ -2158,7 +2304,7 @@ const level = {
spawn.mapRect(-500, -25, 25, 50); //edge shelf
spawn.mapRect(475, -25, 25, 50); //edge shelf
},
intro() {
initial() {
if (level.levelsCleared === 0) { //if this is the 1st level of the game
if (simulation.difficultyMode > 2) spawn.setSpawnList() // hard and why difficulty don't begin with starter mobs
@@ -2216,7 +2362,7 @@ const level = {
} else {
for (let i = 0; i < 60; i++) {
setTimeout(() => {
if (level.levels[level.onLevel] === "intro") spawn.sneaker(2100, -1500 - 50 * i);
if (level.levels[level.onLevel] === "initial") spawn.sneaker(2100, -1500 - 50 * i);
}, 2000 + 500 * i);
}
}
@@ -2457,6 +2603,7 @@ const level = {
document.body.style.backgroundColor = "#ddd";
for (let i = 0; i < 16; i++) powerUps.spawn(4600 + 40 * i, -30, "ammo");
if (simulation.difficultyMode > 4) for (let i = 0; i < 8; i++) powerUps.spawn(4600 + 40 * i, -30, "ammo"); //extra ammo on why difficulty
spawn.mapRect(-1950, 0, 8200, 1800); //ground
spawn.mapRect(-1950, -1500, 1800, 1900); //left wall
@@ -3832,19 +3979,19 @@ const level = {
for (let i = 0; i < 250; i++) spawn.starter(-2700 + 2400 * Math.random(), -1300 - 500 * Math.random())
} else {
if (Math.random() < 0.07 && simulation.difficulty > 35) {
for (let i = 0, len = scale * 0.25 / 6; i < len; ++i) spawn.timeBoss(-1327 - 200 * i, -1525, 60, false); //spawn 1-2 at difficulty 15
for (let i = 0, len = scale * 0.22 / 6; i < len; ++i) spawn.timeBoss(-1327 - 200 * i, -1525, 60, false); //spawn 1-2 at difficulty 15
for (let i = 0, len = scale * 0.1 / 6; i < len; ++i) spawn.bounceBoss(-1327 - 200 * i, -1525, 80, false);
for (let i = 0, len = scale * 0.15 / 6; i < len; ++i) spawn.sprayBoss(-1327 - 200 * i, -1525, 30, false)
for (let i = 0, len = scale * 0.26 / 6; i < len; ++i) spawn.mineBoss(-1327 - 200 * i, -1525, 50, false);
for (let i = 0, len = scale * 0.13 / 6; i < len; ++i) spawn.sprayBoss(-1327 - 200 * i, -1525, 30, false)
for (let i = 0, len = scale * 0.25 / 6; i < len; ++i) spawn.mineBoss(-1327 - 200 * i, -1525, 50, false);
} else {
if (Math.random() < 0.25) {
for (let i = 0, len = scale * 0.25; i < len; ++i) spawn.timeBoss(-1327 - 200 * i, -1525, 80, false); //spawn 1-2 at difficulty 15
for (let i = 0, len = scale * 0.22; i < len; ++i) spawn.timeBoss(-1327 - 200 * i, -1525, 80, false); //spawn 1-2 at difficulty 15
} else if (Math.random() < 0.33) {
for (let i = 0, len = scale * 0.1; i < len; ++i) spawn.bounceBoss(-1327 - 200 * i, -1525, 80, false); //spawn 1-2 at difficulty 15
} else if (Math.random() < 0.5) {
for (let i = 0, len = scale * 0.15; i < len; ++i) spawn.sprayBoss(-1327 - 200 * i, -1525, 30, false) //spawn 2-3 at difficulty 15
for (let i = 0, len = scale * 0.13; i < len; ++i) spawn.sprayBoss(-1327 - 200 * i, -1525, 30, false) //spawn 2-3 at difficulty 15
} else {
for (let i = 0, len = scale * 0.26; i < len; ++i) spawn.mineBoss(-1327 - 200 * i, -1525, 50, false); //spawn 3-4 at difficulty 15
for (let i = 0, len = scale * 0.25; i < len; ++i) spawn.mineBoss(-1327 - 200 * i, -1525, 50, false); //spawn 3-4 at difficulty 15
}
}
}
@@ -3919,6 +4066,7 @@ const level = {
isDoorsLocked = true
for (let i = 0; i < 9; ++i) powerUps.spawn(1200 + 550 * Math.random(), -1700, "ammo")
for (let i = 0; i < 3; ++i) powerUps.spawn(1200 + 550 * Math.random(), -1700, "heal");
if (simulation.difficultyMode > 4) for (let i = 0; i < 8; i++) powerUps.spawn(1200 + 550 * Math.random(), -1700, "ammo"); //extra ammo on why difficulty
const scale = Math.pow(simulation.difficulty, 0.7) //hard around 30, why around 54
if (mobs.mobDeaths < level.levelsCleared && !simulation.isCheating) {
for (let i = 0; i < 250; i++) spawn.starter(300 + 2400 * Math.random(), -1300 - 500 * Math.random())
@@ -12158,7 +12306,10 @@ const level = {
spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
spawn.mapRect(1500, -10, 100, 20);
level.defaultZoom = 1800
simulation.setZoom(1200);
// simulation.setZoom(1200);
simulation.zoomTransition(1200)
document.body.style.backgroundColor = "#daa69f";
color.map = "#600";
@@ -12567,7 +12718,9 @@ const level = {
level.exit.y = -2030;
relocateTo(50, -2050);
simulation.fallHeight = -1000;
simulation.setZoom(1800);
// simulation.setZoom(1800);
simulation.zoomTransition(1800)
templePlayer.startAnim = -1;
templePlayer.drawExit = false;
}

View File

@@ -1092,7 +1092,7 @@ const lore = {
() => {
setTimeout(() => {
lore.anand.text("How ever it thinks it can learn and, I think we showed it that nonviolence is an option,")
lore.anand.text("How ever it thinks it can learn, and I think we showed it that nonviolence is an option,")
}, 1000);
},
() => {
@@ -1116,7 +1116,7 @@ const lore = {
}, 1000);
},
() => {
lore.anand.text("me too")
lore.anand.text("Me too,")
},
() => {
lore.anand.text("but I'm also pretty hungry, wanna go get some food?")

View File

@@ -1350,16 +1350,7 @@ const mobs = {
this.leaveBody = false; // no body since it turned into the bot
}
if (tech.isAddRemoveMaxHealth) {
if (this.isBoss && this.isDropPowerUp) {
powerUps.spawn(this.position.x + 20, this.position.y, "tech", false)
powerUps.spawn(this.position.x - 20, this.position.y, "research", false)
powerUps.spawn(this.position.x - 40, this.position.y, "research", false)
powerUps.spawn(this.position.x + 40, this.position.y, "research", false)
powerUps.spawn(this.position.x, this.position.y + 20, "research", false)
powerUps.spawn(this.position.x, this.position.y - 20, "heal", false)
powerUps.spawn(this.position.x, this.position.y + 40, "heal", false)
powerUps.spawn(this.position.x, this.position.y - 40, "heal", false)
} else {
if (!this.isBoss) {
const amount = 0.005
if (tech.isEnergyHealth) {
if (m.maxEnergy > amount) {
@@ -1371,12 +1362,34 @@ const mobs = {
m.setMaxHealth();
}
}
// if (this.isBoss && this.isDropPowerUp) {
// powerUps.spawn(this.position.x + 20, this.position.y, "tech", false)
// powerUps.spawn(this.position.x - 20, this.position.y, "research", false)
// powerUps.spawn(this.position.x - 40, this.position.y, "research", false)
// powerUps.spawn(this.position.x + 40, this.position.y, "research", false)
// powerUps.spawn(this.position.x, this.position.y + 20, "research", false)
// powerUps.spawn(this.position.x, this.position.y - 20, "heal", false)
// powerUps.spawn(this.position.x, this.position.y + 40, "heal", false)
// powerUps.spawn(this.position.x, this.position.y - 40, "heal", false)
// } else {
// const amount = 0.005
// if (tech.isEnergyHealth) {
// if (m.maxEnergy > amount) {
// tech.healMaxEnergyBonus -= amount
// m.setMaxEnergy();
// }
// } else if (m.maxHealth > amount) {
// tech.extraMaxHealth -= amount //decrease max health
// m.setMaxHealth();
// }
// }
}
if (tech.cloakDuplication && !this.isBoss) {
tech.cloakDuplication -= 0.01
powerUps.setPowerUpMode(); //needed after adjusting duplication chance
}
} else if (tech.isShieldAmmo && this.shield && !this.isExtraShield) {
} else if (tech.isShieldAmmo && this.shield && !this.isExtraShield && this.isDropPowerUp) {
let type = tech.isEnergyNoAmmo ? "heal" : "ammo"
if (Math.random() < 0.4) {
type = "heal"

View File

@@ -539,7 +539,7 @@ const m = {
},
baseHealth: 1,
setMaxHealth() {
m.maxHealth = m.baseHealth + tech.extraMaxHealth + 2.22 * tech.isFallingDamage + 4 * tech.isFlipFlop * tech.isFlipFlopOn * tech.isFlipFlopHealth
m.maxHealth = m.baseHealth + tech.extraMaxHealth + 3 * tech.isFallingDamage + 4 * tech.isFlipFlop * tech.isFlipFlopOn * tech.isFlipFlopHealth
document.getElementById("health-bg").style.width = `${Math.floor(300 * m.maxHealth)}px`
simulation.makeTextLog(`<span class='color-var'>m</span>.<span class='color-h'>maxHealth</span> <span class='color-symbol'>=</span> ${m.maxHealth.toFixed(2)}`)
if (m.health > m.maxHealth) m.health = m.maxHealth;
@@ -564,7 +564,7 @@ const m = {
// if (tech.healthDrain) dmg *= 1 + 3.33 * tech.healthDrain //tech.healthDrain = 0.03 at one stack //cause more damage
if (m.fieldMode === 0 || m.fieldMode === 3) dmg *= 0.973 ** m.coupling
if (tech.isLowHealthDefense) dmg *= 1 - Math.max(0, 1 - m.health) * 0.8
if (tech.isHarmReduceNoKill && m.lastKillCycle + 300 < m.cycle) dmg *= 0.33
if (tech.isHarmReduceNoKill && m.lastKillCycle + 300 < m.cycle) dmg *= 0.26
if (tech.squirrelFx !== 1) dmg *= 0.78//Math.pow(0.78, (tech.squirrelFx - 1) / 0.4)
if (tech.isAddBlockMass && m.isHolding) dmg *= 0.1
if (tech.isSpeedHarm && player.speed > 0.1) dmg *= 1 - Math.min(player.speed * 0.0193, 0.88) //capped at speed of 55
@@ -572,7 +572,7 @@ const m = {
if (tech.isNeutronium && input.field && m.fieldCDcycle < m.cycle) dmg *= 0.05
if (tech.isBotArmor) dmg *= 0.94 ** b.totalBots()
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.27
if (tech.isTurret && m.crouch) dmg *= 0.34;
if (tech.isFirstDer && b.inventory[0] === b.activeGun) dmg *= 0.85 ** b.inventory.length
if (tech.isEnergyHealth) {
@@ -725,7 +725,7 @@ const m = {
tech.isDeathAvoidedThisLevel = true
powerUps.research.changeRerolls(-1)
simulation.makeTextLog(`<span class='color-var'>m</span>.<span class='color-r'>research</span><span class='color-symbol'>--</span><br>${powerUps.research.count}`)
for (let i = 0; i < 5; i++) powerUps.spawn(m.pos.x + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "heal", false);
for (let i = 0; i < 16; i++) powerUps.spawn(m.pos.x + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "heal", false);
m.energy = m.maxEnergy + 0.1
if (m.immuneCycle < m.cycle + 300) m.immuneCycle = m.cycle + 300 //disable this.immuneCycle bonus seconds
simulation.wipe = function () { //set wipe to have trails
@@ -755,7 +755,7 @@ const m = {
powerUps.research.changeRerolls(-1)
simulation.makeTextLog(`<span class='color-var'>m</span>.<span class='color-r'>research</span><span class='color-symbol'>--</span>
<br>${powerUps.research.count}`)
for (let i = 0; i < 5; i++) powerUps.spawn(m.pos.x + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "heal", false);
for (let i = 0; i < 16; i++) powerUps.spawn(m.pos.x + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "heal", false);
if (m.immuneCycle < m.cycle + 300) m.immuneCycle = m.cycle + 300 //disable this.immuneCycle bonus seconds
simulation.wipe = function () { //set wipe to have trails
ctx.fillStyle = "rgba(255,255,255,0.03)";
@@ -1274,23 +1274,29 @@ const m = {
m.drawLeg("#5f5f5f");
m.calcLeg(0, 1);
m.drawLeg("#555");
ctx.rotate(m.angle);
const size = 33
ctx.beginPath();
ctx.arc(0, 0, 30, 0, 2 * Math.PI);
ctx.lineTo(size * 1, size * 0)
ctx.lineTo(size * 0.5, size * 0.866)
ctx.lineTo(size * -0.5, size * 0.866)
ctx.lineTo(size * -1, size * 0)
ctx.lineTo(size * -0.5, size * -0.866)
ctx.lineTo(size * 0.5, size * -0.866)
ctx.lineTo(size * 1, size * 0)
ctx.lineTo(size * 0.5, size * 0)
ctx.fillStyle = m.bodyGradient
ctx.fill();
// ctx.fillStyle = grdRad
// ctx.fill();
ctx.strokeStyle = "#000";
ctx.strokeStyle = "#333";
ctx.lineWidth = 1.5;
ctx.rotate(m.angle);
ctx.beginPath();
ctx.arc(15, 0, 4, 0, 2 * Math.PI);
ctx.fillStyle = "#fff"
ctx.fill();
ctx.beginPath();
ctx.arc(0, 0, 30, 0, 2 * Math.PI);
ctx.arc(15, 0, 4, 0, 2 * Math.PI);
ctx.stroke();
ctx.beginPath();
ctx.arc(15, 0, 3, 0, 2 * Math.PI);
ctx.fillStyle = "#333"
ctx.fill();
ctx.restore();
m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal
powerUps.boost.draw()
@@ -1482,8 +1488,6 @@ const m = {
// console.log(simulation.zoomScale)
simulation.setZoom(1800 + 400 * Math.sin(m.cycle * 0.0075))
}
},
dilate2() {
@@ -1645,6 +1649,95 @@ const m = {
ctx.restore();
}
},
hexagon() {
m.isAltSkin = true
m.color = {
hue: 0,
sat: 0,
light: 100,
}
// m.setFillColors();
m.fillColor = `hsl(${m.color.hue},${m.color.sat}%,${m.color.light}%)`
m.fillColorDark = `hsl(${m.color.hue},${m.color.sat}%,${m.color.light - 35}%)`
let grd = ctx.createLinearGradient(-30, 0, 30, 0);
grd.addColorStop(0, m.fillColorDark);
grd.addColorStop(0.7, m.fillColor);
// grd.addColorStop(1, m.fillColor);
m.bodyGradient = grd
m.draw = function () {
ctx.fillStyle = m.fillColor;
m.walk_cycle += m.flipLegs * m.Vx;
ctx.save();
ctx.globalAlpha = (m.immuneCycle < m.cycle) ? 1 : 0.5 //|| (m.cycle % 40 > 20)
ctx.translate(m.pos.x, m.pos.y);
m.calcLeg(Math.PI, -3);
m.drawLeg("#4a4a4a");
m.calcLeg(0, 0);
m.drawLeg("#333");
ctx.rotate(m.angle);
const size = 32
ctx.beginPath();
ctx.lineTo(size * 1, size * 0)
ctx.lineTo(size * 0.5, size * 0.866)
ctx.lineTo(size * -0.5, size * 0.866)
ctx.lineTo(size * -1, size * 0)
ctx.lineTo(size * -0.5, size * -0.866)
ctx.lineTo(size * 0.5, size * -0.866)
ctx.lineTo(size * 1, size * 0)
ctx.fillStyle = m.bodyGradient
ctx.fill();
ctx.arc(15, 0, 4, 0, 2 * Math.PI);
ctx.strokeStyle = "#333";
ctx.lineWidth = 2;
ctx.stroke();
ctx.restore();
m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal
powerUps.boost.draw()
}
m.drawLeg = function (stroke) {
// if (simulation.mouseInGame.x > m.pos.x) {
if (m.angle > -Math.PI / 2 && m.angle < Math.PI / 2) {
m.flipLegs = 1;
} else {
m.flipLegs = -1;
}
ctx.save();
ctx.scale(m.flipLegs, 1); //leg lines
ctx.beginPath();
ctx.moveTo(m.hip.x, m.hip.y);
ctx.lineTo(m.knee.x, m.knee.y);
ctx.lineTo(m.foot.x, m.foot.y);
ctx.strokeStyle = stroke;
ctx.lineWidth = 6;
ctx.stroke();
//toe lines
ctx.beginPath();
ctx.moveTo(m.foot.x, m.foot.y);
ctx.lineTo(m.foot.x - 15, m.foot.y + 5);
ctx.moveTo(m.foot.x, m.foot.y);
ctx.lineTo(m.foot.x + 15, m.foot.y + 5);
ctx.lineWidth = 3;
ctx.stroke();
//hip joint
ctx.beginPath();
ctx.arc(m.hip.x, m.hip.y, 11, 0, 2 * Math.PI);
//knee joint
ctx.moveTo(m.knee.x + 5, m.knee.y);
ctx.arc(m.knee.x, m.knee.y, 5, 0, 2 * Math.PI);
//foot joint
ctx.moveTo(m.foot.x + 5, m.foot.y);
ctx.arc(m.foot.x, m.foot.y, 5, 0, 2 * Math.PI);
ctx.fillStyle = "#000";
ctx.fill();
// ctx.lineWidth = 2;
// ctx.stroke();
ctx.restore();
}
},
stubs() {
m.isAltSkin = true
m.draw = function () {

View File

@@ -326,7 +326,7 @@ const powerUps = {
return
}
if (tech.isCancelDuplication) {
tech.duplication += 0.043
tech.duplication += 0.047
tech.maxDuplicationEvent()
simulation.makeTextLog(`tech.duplicationChance() <span class='color-symbol'>+=</span> ${0.043}`)
simulation.circleFlare(0.043);
@@ -361,7 +361,7 @@ const powerUps = {
// }
}
if (tech.isAnsatz && powerUps.research.count < 1) {
for (let i = 0; i < 2; i++) powerUps.spawn(m.pos.x + 40 * (Math.random() - 0.5), m.pos.y + 40 * (Math.random() - 0.5), "research", false);
for (let i = 0; i < 3; i++) powerUps.spawn(m.pos.x + 40 * (Math.random() - 0.5), m.pos.y + 40 * (Math.random() - 0.5), "research", false);
}
// document.getElementById("choose-grid").style.display = "none"
document.getElementById("choose-grid").style.visibility = "hidden"
@@ -466,28 +466,30 @@ const powerUps = {
if (m.alive && powerUps.research.count >= cost) {
requestAnimationFrame(cycle);
this.isMakingBots = true
} else {
this.isMakingBots = false
}
if (!simulation.paused && !simulation.isChoosing && !(simulation.cycle % 60)) {
powerUps.research.count -= cost
b.randomBot()
if (tech.renormalization) {
for (let i = 0; i < cost; i++) {
if (Math.random() < 0.46) {
m.fieldCDcycle = m.cycle + 20;
powerUps.spawn(m.pos.x + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "research");
if (!simulation.paused && !simulation.isChoosing && !(simulation.cycle % 60)) {
powerUps.research.count -= cost
b.randomBot()
if (tech.renormalization) {
for (let i = 0; i < cost; i++) {
if (Math.random() < 0.47) {
m.fieldCDcycle = m.cycle + 20;
powerUps.spawn(m.pos.x + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "research");
}
}
}
}
} else {
this.isMakingBots = false
}
}
requestAnimationFrame(cycle);
}
if (tech.isDeathAvoid && document.getElementById("tech-anthropic")) {
document.getElementById("tech-anthropic").innerHTML = `-${powerUps.research.count}`
}
if (tech.renormalization && Math.random() < 0.46 && amount < 0) {
if (tech.renormalization && Math.random() < 0.47 && amount < 0) {
for (let i = 0, len = -amount; i < len; i++) powerUps.spawn(m.pos.x, m.pos.y, "research");
}
if (tech.isRerollHaste) {
@@ -1412,6 +1414,31 @@ const powerUps = {
}
}
}
if (tech.isAddRemoveMaxHealth) {
powerUps.spawn(x + 20, y, "tech", false)
powerUps.spawn(x - 20, y, "research", false)
powerUps.spawn(x - 40, y, "research", false)
powerUps.spawn(x + 40, y, "research", false)
powerUps.spawn(x, y + 20, "research", false)
powerUps.spawn(x, y - 20, "heal", false)
powerUps.spawn(x, y + 40, "heal", false)
powerUps.spawn(x, y - 40, "heal", false)
// if (this.isBoss && this.isDropPowerUp) {
// } else {
// const amount = 0.005
// if (tech.isEnergyHealth) {
// if (m.maxEnergy > amount) {
// tech.healMaxEnergyBonus -= amount
// m.setMaxEnergy();
// }
// } else if (m.maxHealth > amount) {
// tech.extraMaxHealth -= amount //decrease max health
// m.setMaxHealth();
// }
// }
}
}
},
chooseRandomPowerUp(x, y) { //100% chance to drop a random power up //used in spawn.debris
@@ -1501,11 +1528,11 @@ const powerUps = {
},
pauseEjectTech(index) {
if ((tech.isPauseEjectTech || simulation.testing) && !simulation.isChoosing && !tech.tech[index].isNonRefundable) {
if (Math.random() < 0.2 || tech.tech[index].isFromAppliedScience || (tech.tech[index].bonusResearch !== undefined && tech.tech[index].bonusResearch > powerUps.research.count)) {
if (Math.random() < 0.03 || tech.tech[index].isFromAppliedScience || (tech.tech[index].bonusResearch !== undefined && tech.tech[index].bonusResearch > powerUps.research.count)) {
tech.removeTech(index)
// powerUps.spawn(m.pos.x + 40 * (Math.random() - 0.5), m.pos.y + 40 * (Math.random() - 0.5), "research", false);
} else {
powerUps.ejectTech(index)
m.damage(0.06)
}
document.getElementById(`${index}-pause-tech`).style.textDecoration = "line-through"
document.getElementById(`${index}-pause-tech`).style.animation = ""

View File

@@ -24,7 +24,6 @@ const simulation = {
mobs.healthBar();
m.draw();
m.hold();
// v.draw(); //working on visibility work in progress
level.customTopLayer();
simulation.draw.drawMapPath();
b.fire();
@@ -33,10 +32,8 @@ const simulation = {
if (!m.isBodiesAsleep) b.bulletDo();
simulation.drawCircle();
simulation.runEphemera();
// simulation.clip();
ctx.restore();
simulation.drawCursor();
// simulation.pixelGraphics();
},
testingLoop() {
simulation.gravity();
@@ -505,47 +502,52 @@ const simulation = {
simulation.zoom = canvas.height / zoomScale; //sets starting zoom scale
},
zoomTransition(newZoomScale, step = 2) {
//old version
// if (simulation.isAutoZoom) {
// const isBigger = (newZoomScale - simulation.zoomScale > 0) ? true : false;
// requestAnimationFrame(zLoop);
// const currentLevel = level.onLevel
// function zLoop() {
// if (currentLevel !== level.onLevel || simulation.isAutoZoom === false) return //stop the zoom if player goes to a new level
// if (isBigger) {
// simulation.zoomScale += step
// if (simulation.zoomScale >= newZoomScale) {
// simulation.setZoom(newZoomScale);
// return
// }
// } else {
// simulation.zoomScale -= step
// if (simulation.zoomScale <= newZoomScale) {
// simulation.setZoom(newZoomScale);
// return
// }
// }
// simulation.setZoom();
// requestAnimationFrame(zLoop);
// }
// }
//rewrite using the ephemera system
if (simulation.isAutoZoom) {
const isBigger = (newZoomScale - simulation.zoomScale > 0) ? true : false;
requestAnimationFrame(zLoop);
const currentLevel = level.onLevel
function zLoop() {
if (currentLevel !== level.onLevel || simulation.isAutoZoom === false) return //stop the zoom if player goes to a new level
if (isBigger) {
simulation.ephemera.push({
name: "zoom",
count: simulation.testing ? 0 : 120, //cycles before it self removes
currentLevel: level.onLevel,
do() {
this.count--
const step = (newZoomScale - simulation.zoomScale) / this.count
simulation.zoomScale += step
if (simulation.zoomScale >= newZoomScale) {
simulation.setZoom(newZoomScale);
return
if (this.count < 1 && this.currentLevel === level.onLevel && simulation.isAutoZoom) {
simulation.zoomScale = newZoomScale
simulation.removeEphemera(this.name)
}
} else {
simulation.zoomScale -= step
if (simulation.zoomScale <= newZoomScale) {
simulation.setZoom(newZoomScale);
return
}
}
simulation.setZoom();
requestAnimationFrame(zLoop);
}
}
},
zoomInFactor: 0,
startZoomIn(time = 180) {
simulation.zoom = 0;
let count = 0;
requestAnimationFrame(zLoop);
function zLoop() {
simulation.zoom += canvas.height / simulation.zoomScale / time;
count++;
if (count < time) {
requestAnimationFrame(zLoop);
} else {
simulation.setZoom();
}
simulation.setZoom(simulation.zoomScale);
},
})
}
},
translatePlayerAndCamera(where) {
@@ -974,8 +976,8 @@ const simulation = {
} else {
Matter.Body.setVelocity(player, { x: 0, y: 0 });
Matter.Body.setPosition(player, { x: level.enter.x + 50, y: level.enter.y - 20 });
m.damage(0.05 * simulation.difficultyMode);
m.energy -= 0.05 * simulation.difficultyMode
// m.damage(0.02 * simulation.difficultyMode);
// m.energy -= 0.02 * simulation.difficultyMode
// move bots
for (let i = 0; i < bullet.length; i++) {
if (bullet[i].botType) {
@@ -1003,15 +1005,28 @@ const simulation = {
});
}
if (tech.isHealthRecovery) {
const heal = 0.005 * m.maxHealth
m.addHealth(heal)
simulation.drawList.push({ //add dmg to draw queue
x: m.pos.x,
y: m.pos.y,
radius: Math.sqrt(heal) * 150,
color: "rgba(0,255,200,0.5)",
time: 4
});
if (tech.isEnergyHealth) {
if (m.immuneCycle < m.cycle) {
m.energy += m.maxEnergy * 0.005
simulation.drawList.push({ //add dmg to draw queue
x: m.pos.x,
y: m.pos.y,
radius: Math.sqrt(m.maxEnergy * 0.02) * 60,
color: "rgba(0, 204, 255,0.4)", //#0cf
time: 4
});
}
} else {
const heal = 0.005 * m.maxHealth
m.addHealth(heal)
simulation.drawList.push({ //add dmg to draw queue
x: m.pos.x,
y: m.pos.y,
radius: Math.sqrt(heal) * 150,
color: "rgba(0,255,200,0.5)",
time: 4
});
}
}
}
@@ -1355,7 +1370,7 @@ const simulation = {
ctx.textAlign = "center";
ctx.fillText(`(${simulation.mouseInGame.x.toFixed(1)}, ${simulation.mouseInGame.y.toFixed(1)})`, simulation.mouse.x, simulation.mouse.y - 20);
},
sight: { //credit to Cornbread for adding this algorithm to n-gon
sight: { //credit to Cornbread2100 for adding this algorithm to n-gon
// square: 0,
intersectMap: [], //this is precalculated in simulation.draw.lineOfSightPrecalculation()
getIntersection(v1, v1End, domain) {

View File

@@ -22,9 +22,10 @@ const spawn = {
fullPickList: [
"slasher", "slasher", "slasher2", "slasher3",
"hopper", "hopper", "hopMother", "hopMother",
"flutter", "flutter", "flutter",
"stabber", "stabber", "stabber",
"springer", "springer", "springer",
"stinger", "stinger", "stinger",
"flutter", "flutter",
"shooter", "shooter",
"grenadier", "grenadier",
"striker", "striker",
@@ -34,7 +35,7 @@ const spawn = {
],
mobTypeSpawnOrder: [], //preset list of mob names calculated at the start of a run by the randomSeed
mobTypeSpawnIndex: 0, //increases as the mob type cycles
allowedGroupList: ["spinner", "striker", "springer", "laser", "focuser", "beamer", "exploder", "spawner", "shooter", "launcher", "launcherOne", "stabber", "sniper", "pulsar", "grenadier", "slasher", "flutter"],
allowedGroupList: ["spinner", "striker", "springer", "laser", "focuser", "beamer", "exploder", "spawner", "shooter", "launcher", "launcherOne", "stabber", "sniper", "pulsar", "grenadier", "slasher", "flutter", "stinger"],
setSpawnList() { //this is run at the start of each new level to determine the possible mobs for the level
spawn.pickList.splice(0, 1);
const push = spawn.mobTypeSpawnOrder[spawn.mobTypeSpawnIndex++ % spawn.mobTypeSpawnOrder.length]
@@ -3837,6 +3838,202 @@ const spawn = {
// }
};
},
stinger(x, y, radius = 18 + 4 * Math.random()) {
const color = '#5bc'
mobs.spawn(x, y, 7, radius, color);
let me = mob[mob.length - 1];
Matter.Body.setDensity(me, 0.0025); //extra dense //normal is 0.001 //makes effective life much larger
// me.damageReduction = 0.04 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
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.accelMag = 0.0015 + 0.0007 * Math.sqrt(simulation.accelScale);
me.frictionAir = 0.04;
// me.seePlayerFreq = 40 + Math.floor(13 * Math.random())
me.memory = 240;
me.restitution = 0.8;
me.frictionStatic = 0;
me.friction = 0;
me.lookTorque = 0.000001 * (Math.random() > 0.5 ? -1 : 1);
me.fireDir = { x: 0, y: 0 }
spawn.shield(me, x, y);
// me.onDeath = function() {};
me.flapRate = 0.06 + 0.03 * Math.random()
me.flapRadius = 40 + radius * 3
me.do = function () {
this.seePlayerByHistory()
this.checkStatus();
if (this.seePlayer.recall) {
this.force.x += Math.cos(this.angle) * this.accelMag * this.mass
this.force.y += Math.sin(this.angle) * this.accelMag * this.mass
//set direction to turn to fire
if (!(simulation.cycle % this.seePlayerFreq)) {
this.fireDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position));
//dot product can't tell if mob is facing directly away or directly towards, so check if pointed directly away from player every few cycles
const mod = (a, n) => a - Math.floor(a / n) * n
const sub = Vector.sub(m.pos, this.position) //check by comparing different between angles. Give this a nudge if angles are 180 degree different
const diff = mod(Math.atan2(sub.y, sub.x) - this.angle + Math.PI, 2 * Math.PI) - Math.PI
if (Math.abs(diff) > 2.8) this.torque += 0.0002 * this.inertia * Math.random();
}
//rotate towards fireDir
const angle = this.angle + Math.PI / 2;
c = Math.cos(angle) * this.fireDir.x + Math.sin(angle) * this.fireDir.y;
const threshold = 0.4;
const turn = 0.00002 * this.inertia
if (c > threshold) {
this.torque += turn;
} else if (c < -threshold) {
this.torque -= turn;
}
// this.accelMag = 0.0006 + 0.0007 * Math.sqrt(simulation.accelScale);
this.frictionAir = 0.11 + 0.09 * Math.sin(simulation.cycle * this.flapRate - Math.PI / 2)
const flapArc = 0.8 //don't go past 1.57 for normal flaps
ctx.fillStyle = `hsla(${160 + 40 * Math.random()}, 100%, ${25 + 25 * Math.random() * Math.random()}%, 0.2)`; //"rgba(0,235,255,0.3)"; // ctx.fillStyle = `hsla(44, 79%, 31%,0.4)`; //"rgba(0,235,255,0.3)";
this.wing(this.angle + 2.1 + flapArc * Math.sin(simulation.cycle * this.flapRate), this.flapRadius)
this.wing(this.angle - 2.1 - flapArc * Math.sin(simulation.cycle * this.flapRate), this.flapRadius)
const seeRange = 550 + 35 * simulation.difficultyMode;
if (this.distanceToPlayer() < seeRange) {
const vertexCollision = function (v1, v1End, domain) {
for (let i = 0; i < domain.length; ++i) {
let vertices = domain[i].vertices;
const len = vertices.length - 1;
for (let j = 0; j < len; j++) {
results = simulation.checkLineIntersection(v1, v1End, vertices[j], vertices[j + 1]);
if (results.onLine1 && results.onLine2) {
const dx = v1.x - results.x;
const dy = v1.y - results.y;
const dist2 = dx * dx + dy * dy;
if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) {
best = {
x: results.x,
y: results.y,
dist2: dist2,
who: domain[i],
v1: vertices[j],
v2: vertices[j + 1]
};
}
}
}
results = simulation.checkLineIntersection(v1, v1End, vertices[0], vertices[len]);
if (results.onLine1 && results.onLine2) {
const dx = v1.x - results.x;
const dy = v1.y - results.y;
const dist2 = dx * dx + dy * dy;
if (dist2 < best.dist2) {
best = {
x: results.x,
y: results.y,
dist2: dist2,
who: domain[i],
v1: vertices[0],
v2: vertices[len]
};
}
}
}
};
best = {
x: null,
y: null,
dist2: Infinity,
who: null,
v1: null,
v2: null
};
const seeRangeRandom = seeRange - 200 - 150 * Math.random()
const look = {
x: this.position.x + seeRangeRandom * Math.cos(this.angle),
y: this.position.y + seeRangeRandom * Math.sin(this.angle)
};
vertexCollision(this.position, look, map);
vertexCollision(this.position, look, body);
if (!m.isCloak) vertexCollision(this.position, look, [playerBody, playerHead]);
// hitting player
if ((best.who === playerBody || best.who === playerHead) && m.immuneCycle < m.cycle) {
const dmg = 0.002 * simulation.dmgScale;
m.damage(dmg);
//draw damage
ctx.fillStyle = color;
ctx.beginPath();
ctx.arc(best.x, best.y, 5 + dmg * 1500, 0, 2 * Math.PI);
ctx.fill();
}
//draw beam
const vertex = 3
if (best.dist2 === Infinity) best = look;
ctx.beginPath();
ctx.moveTo(this.vertices[vertex].x, this.vertices[vertex].y);
ctx.lineTo(best.x, best.y);
ctx.strokeStyle = color;
ctx.lineWidth = 2;
ctx.setLineDash([50 + 120 * Math.random(), 50 * Math.random()]);
ctx.stroke();
ctx.setLineDash([]);
// ctx.beginPath();
// ctx.arc(this.vertices[vertex].x, this.vertices[vertex].y, 5, 0, 2 * Math.PI); //* this.fireCycle / this.fireDelay
// ctx.fillStyle = color;
// ctx.fill();
}
// else {
// ctx.beginPath();
// ctx.arc(this.vertices[1].x, this.vertices[1].y, 1 + 0.3 * (simulation.cycle % this.laserInterval), 0, 2 * Math.PI); //* this.fireCycle / this.fireDelay
// ctx.fillStyle = color;
// ctx.fill();
// }
}
// else { //flocking behavior (not working yet)
// this.force.x += Math.cos(this.angle) * this.accelMag * this.mass
// this.force.y += Math.sin(this.angle) * this.accelMag * this.mass
// //set direction to turn to fire
// if (!(simulation.cycle % this.seePlayerFreq)) {
// //find nearest mob and maintain a distance
// let nearestMob = null
// let nearestMobDistance = Infinity
// for (let i = 0; i < mob.length; i++) {
// const newMobDistance = Vector.magnitude(Vector.sub(this.position, mob[i].position))
// if (mob[i].isDropPowerUp && mob[i].alive && newMobDistance < nearestMobDistance) { //&& !mob[i].isBoss
// nearestMobDistance = newMobDistance
// nearestMob = mob[i]
// }
// }
// if (nearestMob) {
// // console.log(nearestMob)
// this.fireDir = Vector.normalise(Vector.sub(nearestMob.position, this.position));
// //dot product can't tell if mob is facing directly away or directly towards, so check if pointed directly away from player every few cycles
// const mod = (a, n) => {
// return a - Math.floor(a / n) * n
// }
// const sub = Vector.sub(nearestMob.position, this.position) //check by comparing different between angles. Give this a nudge if angles are 180 degree different
// const diff = mod(Math.atan2(sub.y, sub.x) - this.angle + Math.PI, 2 * Math.PI) - Math.PI
// if (Math.abs(diff) > 2.8) this.torque += 0.0002 * this.inertia * Math.random();
// }
// }
// //rotate towards fireDir
// const angle = this.angle + Math.PI / 2;
// c = Math.cos(angle) * this.fireDir.x + Math.sin(angle) * this.fireDir.y;
// const threshold = 0.4;
// const turn = 0.000025 * this.inertia
// if (c > threshold) {
// this.torque += turn;
// } else if (c < -threshold) {
// this.torque -= turn;
// }
// const flapArc = 0.7 //don't go past 1.57 for normal flaps
// ctx.fillStyle = `hsla(${160 + 40 * Math.random()}, 100%, ${25 + 25 * Math.random() * Math.random()}%, 0.2)`; //"rgba(0,235,255,0.3)"; // ctx.fillStyle = `hsla(44, 79%, 31%,0.4)`; //"rgba(0,235,255,0.3)";
// this.wing(this.angle + Math.PI / 2 + flapArc * Math.sin(simulation.cycle * this.flapRate), this.flapRadius)
// this.wing(this.angle - Math.PI / 2 - flapArc * Math.sin(simulation.cycle * this.flapRate), this.flapRadius)
// }
};
},
beetleBoss(x, y, radius = 50) {
mobs.spawn(x, y, 7, radius, '#16576b');
let me = mob[mob.length - 1];

View File

@@ -231,7 +231,7 @@ const tech = {
// }
// }
// }
if (tech.isDivisor && b.activeGun && b.guns[b.activeGun].ammo % 3 === 0) dmg *= 1.77
if (tech.isDivisor && b.activeGun !== undefined && b.activeGun !== null && b.guns[b.activeGun].ammo % 3 === 0) dmg *= 1.77
if (tech.isNoGroundDamage) dmg *= m.onGround ? 0.85 : 2
if (tech.isDilate) dmg *= 1.5 + 0.6 * Math.sin(m.cycle * 0.0075)
if (tech.isGunChoice && tech.buffedGun === b.inventoryGun) dmg *= 1 + 0.31 * b.inventory.length
@@ -250,11 +250,11 @@ const tech = {
if (tech.isBotDamage) dmg *= 1 + 0.06 * b.totalBots()
if (tech.restDamage > 1 && player.speed < 1) dmg *= tech.restDamage
if (tech.isLowEnergyDamage) dmg *= 1 + 0.7 * Math.max(0, 1 - m.energy)
if (tech.energyDamage) dmg *= 1 + m.energy * 0.22 * tech.energyDamage;
if (tech.energyDamage) dmg *= 1 + m.energy * 0.26 * tech.energyDamage;
if (tech.isDamageFromBulletCount) dmg *= 1 + bullet.length * 0.007
if (tech.isNoFireDamage && m.cycle > m.fireCDcycle + 120) dmg *= 2
if (tech.isNoFireDamage && m.cycle > m.fireCDcycle + 120) dmg *= 2.11
if (tech.isSpeedDamage) dmg *= 1 + Math.min(0.88, player.speed * 0.0193)
if (tech.isDamageAfterKillNoRegen && m.lastKillCycle + 300 > m.cycle) dmg *= 1.83
if (tech.isDamageAfterKillNoRegen && m.lastKillCycle + 300 > m.cycle) dmg *= 1.93
if (tech.isAxion && tech.isHarmMACHO) dmg *= 2 - m.defense()
if (tech.isHarmDamage && m.lastHarmCycle + 480 > m.cycle) dmg *= 3;
if (tech.lastHitDamage && m.lastHit) dmg *= 1 + tech.lastHitDamage * m.lastHit * (2 - m.defense()) // if (!simulation.paused) m.lastHit = 0
@@ -314,7 +314,7 @@ const tech = {
},
tech: [{
name: "tungsten carbide",
description: "<strong>+222</strong> maximum <strong class='color-h'>health</strong><br><strong>lose</strong> <strong class='color-h'>health</strong> after hard <strong>landings</strong>",
description: "<strong>+300</strong> maximum <strong class='color-h'>health</strong><br><strong>lose</strong> <strong class='color-h'>health</strong> after hard <strong>landings</strong>",
maxCount: 1,
count: 0,
frequency: 1,
@@ -328,7 +328,7 @@ const tech = {
tech.hardLanding = 70
tech.isFallingDamage = true;
m.setMaxHealth();
m.addHealth(2.22 / simulation.healScale)
m.addHealth(3 / simulation.healScale)
m.skin.tungsten()
},
remove() {
@@ -402,9 +402,9 @@ const tech = {
isAltRealityTech: true,
isSkin: true,
allowed() {
return !tech.isResearchReality && !tech.isSwitchReality
return !m.isAltSkin && !tech.isResearchReality && !tech.isSwitchReality
},
requires: "not Ψ(t) collapse, many-worlds",
requires: "not skinned, Ψ(t) collapse, many-worlds",
damage: 2.42,
effect() {
m.skin.anodize();
@@ -672,6 +672,43 @@ const tech = {
},
remove() { }
},
{
name: "supply chain",
descriptionFunction() {
return `<strong>double</strong> your current <strong class='color-ammo'>ammo</strong> for all your <strong class='color-g'>guns</strong><br><strong>triple</strong> the frequency of finding <strong>applied science</strong>`
},
maxCount: 9,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return true
},
requires: "",
effect() {
for (let i = 0; i < b.guns.length; i++) {
if (b.guns[i].have) b.guns[i].ammo = Math.floor(2 * b.guns[i].ammo)
}
simulation.makeGunHUD();
for (let i = 0, len = tech.tech.length; i < len; i++) {
if (tech.tech[i].name === "applied science") tech.tech[i].frequency *= 3
}
},
remove() {
if (this.count) {
for (let j = 0; j < this.count; j++) {
for (let i = 0; i < b.guns.length; i++) {
if (b.guns[i].have) b.guns[i].ammo = Math.floor(0.5 * b.guns[i].ammo)
}
}
simulation.makeGunHUD();
for (let i = 0, len = tech.tech.length; i < len; i++) {
if (tech.tech[i].name === "applied science") tech.tech[i].frequency = 2
}
}
}
},
{
name: "applied science",
description: `get a random <strong class='color-g'>gun</strong><strong class='color-m'>tech</strong><br>for each of your <strong class='color-g'>guns</strong>`, //spawn ${powerUps.orb.research(1)} and
@@ -812,40 +849,6 @@ const tech = {
// }
}
},
{
name: "supply chain",
descriptionFunction() {
return `double your current <strong class='color-ammo'>ammo</strong><br><strong>+4%</strong> <strong class='color-junk'>JUNK</strong> to <strong class='color-m'>tech</strong> pool`
},
maxCount: 9,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return true
},
requires: "",
effect() {
for (let i = 0; i < b.guns.length; i++) {
if (b.guns[i].have) b.guns[i].ammo = Math.floor(2 * b.guns[i].ammo)
}
simulation.makeGunHUD();
this.refundAmount += tech.addJunkTechToPool(0.04)
},
refundAmount: 0,
remove() {
for (let j = 0; j < this.count; j++) {
for (let i = 0; i < b.guns.length; i++) {
if (b.guns[i].have) b.guns[i].ammo = Math.floor(0.5 * b.guns[i].ammo)
}
}
simulation.makeGunHUD();
if (this.count > 0 && this.refundAmount > 0) {
tech.removeJunkTechFromPool(this.refundAmount)
this.refundAmount = 0
}
}
},
{
name: "logistics",
description: `${powerUps.orb.ammo()} give <strong>80%</strong> more <strong class='color-ammo'>ammo</strong>, but<br>it's only added to your current <strong class='color-g'>gun</strong>`,
@@ -909,7 +912,7 @@ const tech = {
},
{
name: "non-renewables",
description: `<strong>+88%</strong> <strong class='color-d'>damage</strong><br>${powerUps.orb.ammo()} can't <strong>spawn</strong>`,
description: `<strong>+97%</strong> <strong class='color-d'>damage</strong><br>${powerUps.orb.ammo()} can't <strong>spawn</strong>`,
maxCount: 1,
count: 0,
frequency: 1,
@@ -918,7 +921,7 @@ const tech = {
return !tech.isAmmoFromHealth && !tech.isBoostReplaceAmmo
},
requires: "not catabolism, quasiparticles",
damage: 1.88,
damage: 1.97,
effect() {
tech.damage *= this.damage
tech.isEnergyNoAmmo = true;
@@ -2068,7 +2071,7 @@ const tech = {
},
{
name: "decorrelation",
description: "if your <strong class='color-g'>gun</strong> or <strong class='color-f'>field</strong> are unused for <strong>2</strong> seconds<br><strong>+70%</strong> <strong class='color-defense'>defense</strong>",
description: "if your <strong class='color-g'>gun</strong> or <strong class='color-f'>field</strong> are unused for <strong>2</strong> seconds<br><strong>+77%</strong> <strong class='color-defense'>defense</strong>",
maxCount: 1,
count: 0,
frequency: 1,
@@ -2086,7 +2089,7 @@ const tech = {
},
{
name: "anticorrelation",
description: "if your <strong class='color-g'>gun</strong> or <strong class='color-f'>field</strong> are unused for <strong>2</strong> seconds<br><strong>+100%</strong> <strong class='color-d'>damage</strong>",
description: "if your <strong class='color-g'>gun</strong> or <strong class='color-f'>field</strong> are unused for <strong>2</strong> seconds<br><strong>+111%</strong> <strong class='color-d'>damage</strong>",
maxCount: 1,
count: 0,
frequency: 1,
@@ -2785,7 +2788,7 @@ const tech = {
},
{
name: "overcharge",
description: "<strong>+66</strong> maximum <strong class='color-f'>energy</strong><br><strong>+6%</strong> <strong class='color-junk'>JUNK</strong> to <strong class='color-m'>tech</strong> pool",
description: "<strong>+66</strong> maximum <strong class='color-f'>energy</strong><br><strong>+5%</strong> <strong class='color-junk'>JUNK</strong> to <strong class='color-m'>tech</strong> pool",
maxCount: 9,
count: 0,
frequency: 1,
@@ -2797,7 +2800,7 @@ const tech = {
effect() {
tech.bonusEnergy += 0.66
m.setMaxEnergy()
this.refundAmount += tech.addJunkTechToPool(0.06)
this.refundAmount += tech.addJunkTechToPool(0.05)
},
refundAmount: 0,
remove() {
@@ -2876,7 +2879,7 @@ const tech = {
},
{
name: "parasitism",
description: "if a mob has <strong>died</strong> in the last <strong>5 seconds</strong><br><strong>+83%</strong> <strong class='color-d'>damage</strong>, inhibit <strong class='color-f'>energy</strong> generation",
description: "if a mob has <strong>died</strong> in the last <strong>5 seconds</strong><br><strong>+93%</strong> <strong class='color-d'>damage</strong>, no passive <strong class='color-f'>energy</strong> generation",
maxCount: 1,
count: 0,
frequency: 1,
@@ -2917,7 +2920,10 @@ const tech = {
},
{
name: "recycling",
description: "if a mob has <strong>died</strong> in the last <strong>5 seconds</strong><br>recover <strong>0.5%</strong> of max <strong class='color-h'>health</strong> per second",
descriptionFunction() {
return `if a mob has <strong>died</strong> in the last <strong>5 seconds</strong><br>recover <strong>0.5%</strong> of max ${tech.isEnergyHealth ? "<strong class='color-f'>energy</strong>" : "<strong class='color-h'>health</strong>"} per second`
},
description: "",
maxCount: 1,
count: 0,
frequency: 1,
@@ -2936,7 +2942,7 @@ const tech = {
},
{
name: "torpor",
description: "if a mob has <strong>not died</strong> in the last <strong>5 seconds</strong><br><strong>+66%</strong> <strong class='color-defense'>defense</strong>",
description: "if a mob has <strong>not died</strong> in the last <strong>5 seconds</strong><br><strong>+74%</strong> <strong class='color-defense'>defense</strong>",
maxCount: 1,
count: 0,
frequency: 1,
@@ -3280,7 +3286,7 @@ const tech = {
}, 1000);
},
descriptionFunction() {
return `once per level, instead of <strong>dying</strong><br>use ${powerUps.orb.research(1)} and spawn ${powerUps.orb.heal(5)}`
return `once per level, instead of <strong>dying</strong><br>use ${powerUps.orb.research(1)} and spawn ${powerUps.orb.heal(16)}`
},
maxCount: 1,
count: 0,
@@ -3381,7 +3387,7 @@ const tech = {
{
name: "Ψ(t) collapse",
link: `<a target="_blank" href='https://en.wikipedia.org/wiki/Wave_function_collapse' class="link">Ψ(t) collapse</a>`,
description: `spawn ${powerUps.orb.research(16)}<br>after you <strong class='color-r'>research</strong> enter an <strong class='alt'>alternate reality</strong>`,
description: `spawn ${powerUps.orb.research(21)}<br>after you <strong class='color-r'>research</strong> enter an <strong class='alt'>alternate reality</strong>`,
maxCount: 1,
count: 0,
frequency: 1,
@@ -3391,7 +3397,7 @@ const tech = {
return !tech.isSwitchReality && !tech.isCollisionRealitySwitch && !tech.isJunkResearch
},
requires: "not many-worlds, Hilbert space, pseudoscience",
bonusResearch: 16,
bonusResearch: 21,
effect() {
tech.isResearchReality = true;
for (let i = 0; i < this.bonusResearch; i++) powerUps.spawn(m.pos.x + Math.random() * 60, m.pos.y + Math.random() * 60, "research", false);
@@ -3431,7 +3437,7 @@ const tech = {
},
{
name: "renormalization",
description: `<strong>46%</strong> chance to spawn ${powerUps.orb.research(1)} after consuming ${powerUps.orb.research(1)}<br><strong>+3%</strong> <strong class='color-junk'>JUNK</strong> to <strong class='color-m'>tech</strong> pool`,
description: `<strong>47%</strong> chance to spawn ${powerUps.orb.research(1)} after consuming ${powerUps.orb.research(1)}<br><strong>+5%</strong> <strong class='color-junk'>JUNK</strong> to <strong class='color-m'>tech</strong> pool`,
maxCount: 1,
count: 0,
frequency: 2,
@@ -3442,7 +3448,7 @@ const tech = {
requires: "at least 4 research, not superdeterminism",
effect() {
tech.renormalization = true;
this.refundAmount += tech.addJunkTechToPool(0.03)
this.refundAmount += tech.addJunkTechToPool(0.05)
},
refundAmount: 0,
@@ -3481,7 +3487,7 @@ const tech = {
},
{
name: "ansatz",
description: `after choosing a <strong class='color-f'>field</strong>, <strong class='color-m'>tech</strong>, or <strong class='color-g'>gun</strong><br>if you have no ${powerUps.orb.research(1)} in your inventory spawn ${powerUps.orb.research(2)}`,
description: `after choosing a <strong class='color-f'>field</strong>, <strong class='color-m'>tech</strong>, or <strong class='color-g'>gun</strong><br>if you have no ${powerUps.orb.research(1)} in your inventory spawn ${powerUps.orb.research(3)}`,
maxCount: 1,
count: 0,
frequency: 1,
@@ -3501,17 +3507,17 @@ const tech = {
name: "Bayesian statistics",
// description: `for each ${powerUps.orb.research(1)} in your inventory<br><strong>+3.8%</strong> <strong class='color-d'>damage</strong>`,
descriptionFunction() {
return `spawn ${powerUps.orb.research(this.bonusResearch)}<br><strong>+3%</strong> <strong class='color-d'>damage</strong> per ${powerUps.orb.research(1)} <em>(${(3 * powerUps.research.count).toFixed(0)}%)</em>`
return `spawn ${powerUps.orb.research(this.bonusResearch)}<br><strong>+3%</strong> <strong class='color-d'>damage</strong> per ${powerUps.orb.research(1)} in your inventory <em>(${(3 * powerUps.research.count).toFixed(0)}%)</em>`
},
maxCount: 1,
count: 0,
frequency: 2,
frequencyDefault: 2,
allowed() {
return powerUps.research.count > 2 || build.isExperimentSelection
return powerUps.research.count > 1 || build.isExperimentSelection
},
requires: "at least 3 research",
bonusResearch: 3,
requires: "at least 2 research",
bonusResearch: 6,
effect() {
powerUps.spawnDelay("research", this.bonusResearch)
tech.isRerollDamage = true;
@@ -3526,7 +3532,7 @@ const tech = {
{
name: "mass production",
descriptionFunction() {
return `<strong class='color-m'>tech</strong> always have <strong>+3</strong> choices to spawn<br>${powerUps.orb.ammo(10)} ${powerUps.orb.heal(10)} &nbsp;&nbsp; or ${powerUps.orb.research(7)}`
return `<strong class='color-m'>tech</strong> always have <strong>+3</strong> choices to spawn<br>options for &nbsp; ${powerUps.orb.ammo(1)} &nbsp; or &nbsp; ${powerUps.orb.heal(1)} &nbsp; or &nbsp; ${powerUps.orb.research(1)}`
},
// description: `<strong class='color-m'>tech</strong> always have <strong>+3</strong> choices to spawn<br>${powerUps.orb.ammo(8)} ${powerUps.orb.heal(8)} &nbsp;&nbsp; or ${powerUps.orb.research(5)}`,
maxCount: 1,
@@ -3544,8 +3550,10 @@ const tech = {
},
{
name: "research",
description: `spawn ${powerUps.orb.research(7)}`,
maxCount: 1,
descriptionFunction() {
return `spawn ${this.value > 36 ? this.value + powerUps.orb.research(1) : powerUps.orb.research(this.value)}<br>next time this effect is improved by ${powerUps.orb.research(5)}`
},
maxCount: 9,
count: 0,
frequency: 0,
frequencyDefault: 0,
@@ -3553,15 +3561,19 @@ const tech = {
isMassProduction: true,
allowed() { return true },
requires: "",
value: 8,
effect() {
powerUps.spawnDelay("research", 7);
powerUps.spawnDelay("research", this.value);
this.value += 5
},
remove() { }
},
{
name: "ammo",
description: `spawn ${powerUps.orb.ammo(10)}`,
maxCount: 1,
descriptionFunction() {
return `spawn ${this.value > 33 ? this.value + powerUps.orb.ammo(1) : powerUps.orb.ammo(this.value)}<br>next time this effect is improved by ${powerUps.orb.ammo(7)}`
},
maxCount: 9,
count: 0,
frequency: 0,
frequencyDefault: 0,
@@ -3569,26 +3581,30 @@ const tech = {
isMassProduction: true,
allowed() { return true },
requires: "",
value: 10,
effect() {
powerUps.spawnDelay("ammo", 10);
powerUps.spawnDelay("ammo", this.value);
this.value += 7
},
remove() { }
},
{
name: "heals",
descriptionFunction() {
return `spawn ${powerUps.orb.heal(10)}`
return `spawn ${this.value > 30 ? this.value + powerUps.orb.heal(1) : powerUps.orb.heal(this.value)}<br>next time this effect is improved by ${powerUps.orb.heal(7)}`
},
maxCount: 1,
maxCount: 9,
count: 0,
frequency: 0,
frequencyDefault: 0,
isNonRefundable: true,
isMassProduction: true,
allowed() { return true },
requires: "mass production",
requires: "",
value: 10,
effect() {
powerUps.spawnDelay("heal", 10);
powerUps.spawnDelay("heal", this.value);
this.value += 7
},
remove() { }
},
@@ -3624,7 +3640,7 @@ const tech = {
effect() {
tech.isBrainstorm = true
tech.isBrainstormActive = false
tech.brainStormDelay = 1800 - simulation.difficultyMode * 100
tech.brainStormDelay = 2000 - simulation.difficultyMode * 100
},
remove() {
tech.isBrainstorm = false
@@ -3921,7 +3937,11 @@ const tech = {
},
{
name: "paradigm shift",
description: `when <strong>paused</strong> clicking a <strong class='color-m'>tech</strong> <strong>ejects</strong> it<br>with a <strong>20%</strong> chance to remove without <strong>ejecting</strong>`,
// description: `when <strong>paused</strong> clicking a <strong class='color-m'>tech</strong> <strong>ejects</strong> it<br>with a <strong>20%</strong> chance to remove without <strong>ejecting</strong>`,
// description: `when <strong>paused</strong> clicking a <strong class='color-m'>tech</strong> <strong>ejects</strong> it<br>and a <strong>20%</strong> chance to remove without <strong>ejecting</strong>`,
descriptionFunction() {
return `when <strong>paused</strong> clicking a <strong class='color-m'>tech</strong> <strong>ejects</strong> it<br><strong>6</strong> ${tech.isEnergyHealth ? "<strong class='color-f'>energy</strong>" : "<strong class='color-h'>health</strong>"} each time and a <strong>3%</strong> chance to fail`
},
maxCount: 1,
count: 0,
frequency: 1,
@@ -4154,7 +4174,7 @@ const tech = {
},
{
name: "futures exchange",
description: "clicking <strong class='color-cancel'>cancel</strong> for a <strong class='color-f'>field</strong>, <strong class='color-m'>tech</strong>, or <strong class='color-g'>gun</strong><br>gives <strong>+4.3%</strong> power up <strong class='color-dup'>duplication</strong> chance",
description: "clicking <strong class='color-cancel'>cancel</strong> for a <strong class='color-f'>field</strong>, <strong class='color-m'>tech</strong>, or <strong class='color-g'>gun</strong><br>gives <strong>+4.7%</strong> power up <strong class='color-dup'>duplication</strong> chance",
// descriptionFunction() {
// return `clicking <strong style = 'font-size:150%;'>×</strong> to <strong>cancel</strong> a <strong class='color-f'>field</strong>, <strong class='color-m'>tech</strong>, or <strong class='color-g'>gun</strong><br>gives <strong>+${4.9 - 0.15*simulation.difficultyMode}%</strong> power up <strong class='color-dup'>duplication</strong> chance`
// },
@@ -4177,7 +4197,7 @@ const tech = {
},
{
name: "replication",
description: "<strong>+9%</strong> chance to <strong class='color-dup'>duplicate</strong> spawned <strong>power ups</strong><br><strong>+33%</strong> <strong class='color-junk'>JUNK</strong> to <strong class='color-m'>tech</strong> pool",
description: "<strong>+10%</strong> chance to <strong class='color-dup'>duplicate</strong> spawned <strong>power ups</strong><br><strong>+33%</strong> <strong class='color-junk'>JUNK</strong> to <strong class='color-m'>tech</strong> pool",
maxCount: 9,
count: 0,
frequency: 1,
@@ -4187,7 +4207,7 @@ const tech = {
},
requires: "below 100% duplication chance",
effect() {
tech.duplicateChance += 0.09
tech.duplicateChance += 0.1
powerUps.setPowerUpMode(); //needed after adjusting duplication chance
if (!build.isExperimentSelection && !simulation.isTextLogOpen) simulation.circleFlare(0.11);
this.refundAmount += tech.addJunkTechToPool(0.33)
@@ -4204,7 +4224,7 @@ const tech = {
},
{
name: "stimulated emission",
description: "<strong>+17%</strong> chance to <strong class='color-dup'>duplicate</strong> spawned <strong>power ups</strong>,<br>but after a <strong>collision</strong> eject <strong>1</strong> <strong class='color-m'>tech</strong>",
description: "<strong>+19%</strong> chance to <strong class='color-dup'>duplicate</strong> spawned <strong>power ups</strong>,<br>but after a <strong>collision</strong> eject <strong>1</strong> <strong class='color-m'>tech</strong>",
maxCount: 1,
count: 0,
frequency: 1,
@@ -4328,6 +4348,34 @@ const tech = {
}
}
},
{
name: "strange loop",
// description: `<strong>+11%</strong> <strong class='color-d'>damage</strong><br><strong>removing</strong> this doubles it's damage if you take it again`,
description: `<strong>+9%</strong> <strong class='color-d'>damage</strong><br><span style = 'font-size:87%;'><strong>removing</strong> this gives <strong>strange attractor</strong> and <strong>null hypothesis</strong></span>`,
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
isBadRandomOption: true,
allowed() {
return true
},
requires: "",
damage: 1.09,
effect() {
tech.damage *= this.damage
},
remove() {
if (this.count > 0 && m.alive) {
tech.damage /= this.damage
this.frequency = 0
requestAnimationFrame(() => {
tech.giveTech("null hypothesis")
tech.giveTech("strange attractor")
});
}
}
},
{
name: "null hypothesis",
description: `<strong>+8%</strong> <strong class='color-d'>damage</strong><br><strong>removing</strong> this spawns ${powerUps.orb.research(15)}`,
@@ -4352,6 +4400,35 @@ const tech = {
}
}
},
{
name: "martingale",
descriptionFunction() {
return `<span style = 'font-size:95%;'><strong>+${(100 * this.damage).toFixed(0)}%</strong> <strong class='color-d'>damage</strong>. After removing this there is a <strong>50%</strong><br>chance to get it back with <strong>double</strong> its <strong class='color-d'>damage</strong></span>`
},
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
isBadRandomOption: true,
allowed() {
return true
},
requires: "",
damage: 0.11,
effect() {
tech.damage *= 1 + this.damage
},
remove() {
if (this.count > 0 && m.alive) {
tech.damage /= 1 + this.damage
if (Math.random() < 0.5) {
this.damage *= 2
requestAnimationFrame(() => { tech.giveTech("chaos theory") });
}
this.frequency = 0
}
}
},
{
name: "Born rule",
description: "<strong>remove</strong> all current <strong class='color-m'>tech</strong><br>spawn new <strong class='color-m'>tech</strong> to replace them",
@@ -4744,6 +4821,8 @@ const tech = {
b.guns[0].ammoPack = b.guns[0].defaultAmmoPack;
if (b.guns[0].recordedAmmo) b.guns[0].ammo = b.guns[0].recordedAmmo
simulation.updateGunHUD();
if (this.count) requestAnimationFrame(() => { simulation.updateGunHUD(); });
}
tech.isIceCrystals = false;
if (b.guns[0].ammo === Infinity) b.guns[0].ammo = 0
@@ -5377,6 +5456,7 @@ const tech = {
if (this.count > 0 && b.guns[3].savedAmmo !== undefined) {
b.guns[3].ammo = b.guns[3].savedAmmo
simulation.updateGunHUD();
requestAnimationFrame(() => { simulation.updateGunHUD(); });
} else if (b.guns[3].ammo === Infinity) {
b.guns[3].ammo = 0
}
@@ -7071,7 +7151,7 @@ const tech = {
},
{
name: "induction furnace",
description: "after using <strong>harpoon</strong> or <strong>grapple</strong> to collect <strong>power ups</strong><br><strong>+77%</strong> <strong>harpoon</strong> or <strong>grapple</strong> <strong class='color-d'>damage</strong> for 8 seconds",
description: "after using <strong>harpoon</strong>/<strong>grapple</strong> to collect <strong>power ups</strong><br><strong>+77%</strong> <strong>harpoon</strong> or <strong>grapple</strong> <strong class='color-d'>damage</strong> for 8 seconds",
isGunTech: true,
maxCount: 1,
count: 0,
@@ -7091,7 +7171,7 @@ const tech = {
},
{
name: "brittle",
description: "<strong>+88%</strong> <strong>harpoon</strong> and <strong>grapple</strong> <strong class='color-d'>damage</strong><br>to <strong>mobs</strong> at maximum <strong>health</strong>",
description: "<strong>+88%</strong> <strong>harpoon</strong>/<strong>grapple</strong> <strong class='color-d'>damage</strong><br>to <strong>mobs</strong> at maximum <strong>health</strong>",
isGunTech: true,
maxCount: 1,
count: 0,
@@ -7595,7 +7675,7 @@ const tech = {
{
name: "electronegativity",
descriptionFunction() {
return `<strong>+0.22%</strong> <strong class='color-d'>damage</strong> per current stored <strong class='color-f'>energy</strong><br><em>(+${(22 * m.maxEnergy).toFixed(0)}% damage at max energy)</em>`
return `<strong>+0.26%</strong> <strong class='color-d'>damage</strong> per current stored <strong class='color-f'>energy</strong><br><em>(+${(27 * m.maxEnergy).toFixed(0)}% damage at max energy)</em>`
},
// description: "<strong>+1%</strong> <strong class='color-d'>damage</strong> per <strong>8</strong> stored <strong class='color-f'>energy</strong>",
isFieldTech: true,