let powerUp = []; const powerUps = { totalPowerUps: 0, //used for tech that count power ups at the end of a level choose(type, index) { if (type === "gun") { b.giveGuns(index) let text = `b.giveGuns("${b.guns[index].name}")` if (b.inventory.length === 1) text += `
input.key.gun = ["MouseLeft"]` if (b.inventory.length === 2) text += `
input.key.nextGun = ["${input.key.nextGun}","MouseWheel"]
input.key.previousGun = ["${input.key.previousGun}","MouseWheel"]` simulation.makeTextLog(text); } else if (type === "field") { mech.setField(index) simulation.makeTextLog(`mech.setField("${mech.fieldUpgrades[mech.fieldMode].name}")`); } else if (type === "tech") { tech.giveTech(index) simulation.makeTextLog(`tech.giveTech("${tech.tech[index].name}")`); } powerUps.endDraft(type); }, showDraft() { // document.getElementById("choose-grid").style.gridTemplateColumns = "repeat(2, minmax(370px, 1fr))" document.getElementById("choose-grid").style.display = "grid" document.getElementById("choose-background").style.display = "inline" document.body.style.cursor = "auto"; if (tech.isExtraChoice) { document.body.style.overflowY = "scroll"; document.body.style.overflowX = "hidden"; } simulation.paused = true; simulation.isChoosing = true; //stops p from un pausing on key down build.pauseGrid(true) }, endDraft(type, isCanceled = false) { if (isCanceled) { if (tech.isCancelDuplication) tech.cancelCount++ if (tech.isCancelRerolls) { let spawnType = (mech.health < 0.25 || tech.isEnergyNoAmmo) ? "heal" : "ammo" if (Math.random() < 0.33) { spawnType = "heal" } else if (Math.random() < 0.5 && !tech.isSuperDeterminism) { spawnType = "reroll" } for (let i = 0; i < 6; i++) powerUps.spawn(mech.pos.x + 40 * (Math.random() - 0.5), mech.pos.y + 40 * (Math.random() - 0.5), spawnType, false); } if (tech.isBanish && type === 'tech') { // banish rerolled tech by adding them to the list of banished tech const banishLength = tech.isDeterminism ? 1 : 3 + tech.isExtraChoice * 2 if (powerUps.tech.choiceLog.length > banishLength || powerUps.tech.choiceLog.length === banishLength) { //I'm not sure this check is needed for (let i = 0; i < banishLength; i++) { powerUps.tech.banishLog.push(powerUps.tech.choiceLog[powerUps.tech.choiceLog.length - 1 - i]) } } simulation.makeTextLog(`${Math.max(0,powerUps.tech.lastTotalChoices - powerUps.tech.banishLog.length)} estimated tech choices remaining`) } } if (tech.manyWorlds && powerUps.reroll.rerolls === 0) { for (let i = 0; i < 2; i++) powerUps.spawn(mech.pos.x + 40 * (Math.random() - 0.5), mech.pos.y + 40 * (Math.random() - 0.5), "reroll", false); } document.getElementById("choose-grid").style.display = "none" document.getElementById("choose-background").style.display = "none" document.body.style.cursor = "none"; document.body.style.overflow = "hidden" simulation.paused = false; simulation.isChoosing = false; //stops p from un pausing on key down mech.immuneCycle = mech.cycle + 60; //player is immune to collision damage for 30 cycles build.unPauseGrid() requestAnimationFrame(cycle); }, reroll: { rerolls: 0, name: "reroll", color: "#f7b", size() { return 20; }, effect() { powerUps.reroll.changeRerolls(1) }, changeRerolls(amount) { powerUps.reroll.rerolls += amount if (powerUps.reroll.rerolls < 0) { powerUps.reroll.rerolls = 0 } else { simulation.makeTextLog(`powerUps.reroll.rerolls += ${amount}`) //
${powerUps.reroll.rerolls} } if (tech.isRerollBots) { const limit = 5 for (; powerUps.reroll.rerolls > limit - 1; powerUps.reroll.rerolls -= limit) { b.randomBot() if (tech.renormalization) { for (let i = 0; i < limit; i++) { if (Math.random() < 0.37) { mech.fieldCDcycle = mech.cycle + 30; powerUps.spawn(mech.pos.x, mech.pos.y, "reroll"); } } } } } if (tech.isDeathAvoid && document.getElementById("tech-anthropic")) { document.getElementById("tech-anthropic").innerHTML = `-${powerUps.reroll.rerolls}` } if (tech.renormalization && Math.random() < 0.37 && amount < 0) powerUps.spawn(mech.pos.x, mech.pos.y, "reroll"); if (tech.isRerollHaste) { if (powerUps.reroll.rerolls === 0) { tech.rerollHaste = 0.66; b.setFireCD(); } else { tech.rerollHaste = 1; b.setFireCD(); } } }, use(type) { //runs when you actually reroll a list of selections, type can be field, gun, or tech powerUps.reroll.changeRerolls(-1) // simulation.makeTextLog(`mech.rerolls-- //
${powerUps.reroll.rerolls}`) if (tech.isBanish && type === 'tech') { // banish rerolled tech const banishLength = tech.isDeterminism ? 1 : 3 + tech.isExtraChoice * 2 if (powerUps.tech.choiceLog.length > banishLength || powerUps.tech.choiceLog.length === banishLength) { //I'm not sure this check is needed for (let i = 0; i < banishLength; i++) { powerUps.tech.banishLog.push(powerUps.tech.choiceLog[powerUps.tech.choiceLog.length - 1 - i]) } } simulation.makeTextLog(`${Math.max(0,powerUps.tech.lastTotalChoices - powerUps.tech.banishLog.length)} estimated tech choices remaining`) } powerUps[type].effect(); }, }, heal: { name: "heal", color: "#0eb", size() { return 40 * (simulation.healScale ** 0.25) * Math.sqrt(tech.largerHeals) * Math.sqrt(0.1 + Math.random() * 0.5); //(simulation.healScale ** 0.25) gives a smaller radius as heal scale goes down }, effect() { if (!tech.isEnergyHealth && mech.alive) { const heal = tech.largerHeals * (this.size / 40 / Math.sqrt(tech.largerHeals) / (simulation.healScale ** 0.25)) ** 2 //heal scale is undone here because heal scale is properly affected on mech.addHealth() if (heal > 0) { const healOutput = Math.min(mech.maxHealth - mech.health, heal) * simulation.healScale mech.addHealth(heal); simulation.makeTextLog(`mech.health += ${(healOutput).toFixed(3)}`) //
${mech.health.toFixed(3)} // simulation.makeTextLog("
  heal " + (Math.min(mech.maxHealth - mech.health, heal) * simulation.healScale * 100).toFixed(0) + "%", 300) } } if (tech.healGiveMaxEnergy) { tech.healMaxEnergyBonus += 0.04 mech.setMaxEnergy(); } }, spawn(x, y, size) { //used to spawn a heal with a specific size / heal amount, not normally used powerUps.directSpawn(x, y, "heal", false, null, size) if (Math.random() < tech.duplicationChance()) { powerUps.directSpawn(x, y, "heal", false, null, size) powerUp[powerUp.length - 1].isBonus = true } } }, ammo: { name: "ammo", color: "#467", size() { return 17; }, effect() { //give ammo to all guns in inventory if (tech.isAmmoForGun && b.inventory.length > 0) { const target = b.guns[b.activeGun] const ammoAdded = Math.ceil(Math.random() * target.ammoPack) + Math.ceil(Math.random() * target.ammoPack) target.ammo += ammoAdded // simulation.makeTextLog(`
  ${ammoAdded} ammo added`, 300) simulation.makeTextLog(`${target.name}.ammo += ${ammoAdded}
${target.ammo}`) } else { let text = ''; for (let i = 0, len = b.inventory.length; i < len; i++) { const target = b.guns[b.inventory[i]] if (target.ammo !== Infinity) { const ammoAdded = Math.ceil(Math.random() * target.ammoPack) target.ammo += ammoAdded if (i !== 0) text += "
" text += `${target.name}.ammo += ${ammoAdded}` } } simulation.makeTextLog(text) } simulation.updateGunHUD(); } }, field: { name: "field", color: "#0cf", size() { return 45; }, choiceLog: [], //records all previous choice options effect() { function pick(who, skip1 = -1, skip2 = -1, skip3 = -1, skip4 = -1) { let options = []; for (let i = 1; i < who.length; i++) { if (i !== mech.fieldMode && i !== skip1 && i !== skip2 && i !== skip3 && i !== skip4) options.push(i); } //remove repeats from last selection const totalChoices = tech.isDeterminism ? 1 : 3 + tech.isExtraChoice * 2 if (powerUps.field.choiceLog.length > totalChoices || powerUps.field.choiceLog.length === totalChoices) { //make sure this isn't the first time getting a power up and there are previous choices to remove for (let i = 0; i < totalChoices; i++) { //repeat for each choice from the last selection if (options.length > totalChoices) { for (let j = 0, len = options.length; j < len; j++) { if (powerUps.field.choiceLog[powerUps.field.choiceLog.length - 1 - i] === options[j]) { options.splice(j, 1) //remove previous choice from option pool break } } } } } if (options.length > 0) { return options[Math.floor(Math.random() * options.length)] } } let choice1 = pick(mech.fieldUpgrades) let choice2 = -1 let choice3 = -1 if (choice1 > -1) { let text = "" if (!tech.isDeterminism) text += `
` text += `

field

` text += `
  ${mech.fieldUpgrades[choice1].name}
${mech.fieldUpgrades[choice1].description}
` if (!tech.isDeterminism) { choice2 = pick(mech.fieldUpgrades, choice1) if (choice2 > -1) text += `
  ${mech.fieldUpgrades[choice2].name}
${mech.fieldUpgrades[choice2].description}
` choice3 = pick(mech.fieldUpgrades, choice1, choice2) if (choice3 > -1) text += `
  ${mech.fieldUpgrades[choice3].name}
${mech.fieldUpgrades[choice3].description}
` } if (tech.isExtraChoice) { let choice4 = pick(mech.fieldUpgrades, choice1, choice2, choice3) if (choice4 > -1) text += `
  ${mech.fieldUpgrades[choice4].name}
${mech.fieldUpgrades[choice4].description}
` let choice5 = pick(mech.fieldUpgrades, choice1, choice2, choice3, choice4) if (choice5 > -1) text += `
  ${mech.fieldUpgrades[choice5].name}
${mech.fieldUpgrades[choice5].description}
` powerUps.field.choiceLog.push(choice4) powerUps.field.choiceLog.push(choice5) } powerUps.field.choiceLog.push(choice1) powerUps.field.choiceLog.push(choice2) powerUps.field.choiceLog.push(choice3) if (powerUps.reroll.rerolls) { text += `
` for (let i = 0, len = Math.min(powerUps.reroll.rerolls, 30); i < len; i++) text += `
` text += `
reroll
` } //(${powerUps.reroll.rerolls}) // text += `
${simulation.SVGrightMouse} activate the shield with the right mouse
fields shield you from damage
and let you pick up and throw blocks
` document.getElementById("choose-grid").innerHTML = text powerUps.showDraft(); } else { powerUps.giveRandomAmmo() } } }, tech: { name: "tech", color: "hsl(246,100%,77%)", //"#a8f", size() { return 42; }, choiceLog: [], //records all previous choice options lastTotalChoices: 0, //tracks how many tech were available for random selection last time a tech was picked up banishLog: [], //records all tech permanently removed from the selection pool effect() { if (mech.alive) { function pick(skip1 = -1, skip2 = -1, skip3 = -1, skip4 = -1) { let options = []; for (let i = 0; i < tech.tech.length; i++) { if (tech.tech[i].count < tech.tech[i].maxCount && i !== skip1 && i !== skip2 && i !== skip3 && i !== skip4 && tech.tech[i].allowed()) { options.push(i); } } powerUps.tech.lastTotalChoices = options.length //this is recorded so that banish can know how many tech were available if (tech.isBanish) { //remove banished tech from last selection for (let i = 0; i < powerUps.tech.banishLog.length; i++) { for (let j = 0; j < options.length; j++) { if (powerUps.tech.banishLog[i] === options[j]) { options.splice(j, 1) break } } } } else { //remove repeats from last selection const totalChoices = tech.isDeterminism ? 1 : 3 + tech.isExtraChoice * 2 if (powerUps.tech.choiceLog.length > totalChoices || powerUps.tech.choiceLog.length === totalChoices) { //make sure this isn't the first time getting a power up and there are previous choices to remove for (let i = 0; i < totalChoices; i++) { //repeat for each choice from the last selection if (options.length > totalChoices) { for (let j = 0, len = options.length; j < len; j++) { if (powerUps.tech.choiceLog[powerUps.tech.choiceLog.length - 1 - i] === options[j]) { options.splice(j, 1) //remove previous choice from option pool break } } } } } } if (options.length > 0) { const choose = options[Math.floor(Math.random() * options.length)] const isCount = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count+1}x)` : ""; if (tech.tech[choose].isFieldTech) { text += `
        ${tech.tech[choose].name} ${isCount}
${tech.tech[choose].description}
` } else if (tech.tech[choose].isGunTech) { text += `
        ${tech.tech[choose].name} ${isCount}
${tech.tech[choose].description}
` } else { text += `
  ${tech.tech[choose].name} ${isCount}
${tech.tech[choose].description}
` } // text += `
  ${tech.tech[choose].name}
${tech.tech[choose].description}
` return choose } } let text = "" if (!tech.isDeterminism) text += `
` text += `

tech

` let choice1 = pick() let choice2 = -1 let choice3 = -1 if (choice1 > -1) { if (!tech.isDeterminism) { choice2 = pick(choice1) // if (choice2 > -1) text += `
  ${tech.tech[choice2].name}
${tech.tech[choice2].description}
` choice3 = pick(choice1, choice2) // if (choice3 > -1) text += `
  ${tech.tech[choice3].name}
${tech.tech[choice3].description}
` } if (tech.isExtraChoice) { let choice4 = pick(choice1, choice2, choice3) // if (choice4 > -1) text += `
  ${tech.tech[choice4].name}
${tech.tech[choice4].description}
` let choice5 = pick(choice1, choice2, choice3, choice4) // if (choice5 > -1) text += `
  ${tech.tech[choice5].name}
${tech.tech[choice5].description}
` powerUps.tech.choiceLog.push(choice4) powerUps.tech.choiceLog.push(choice5) } powerUps.tech.choiceLog.push(choice1) powerUps.tech.choiceLog.push(choice2) powerUps.tech.choiceLog.push(choice3) // if (powerUps.reroll.rerolls) text += `
  reroll ${powerUps.reroll.rerolls}
` if (powerUps.reroll.rerolls) { text += `
` for (let i = 0, len = Math.min(powerUps.reroll.rerolls, 30); i < len; i++) text += `
` text += `
reroll
` } document.getElementById("choose-grid").innerHTML = text powerUps.showDraft(); } else { if (tech.isBanish) { for (let i = 0, len = tech.tech.length; i < len; i++) { if (tech.tech[i].name === "erase") powerUps.ejectTech(i) } simulation.makeTextLog(`No tech left
erased tech have been recovered`) powerUps.spawn(mech.pos.x, mech.pos.y, "tech"); powerUps.endDraft("tech"); } else { powerUps.giveRandomAmmo() } } } } }, gun: { name: "gun", color: "#26a", size() { return 35; }, choiceLog: [], //records all previous choice options effect() { function pick(who, skip1 = -1, skip2 = -1, skip3 = -1, skip4 = -1) { let options = []; for (let i = 0; i < who.length; i++) { if (!who[i].have && i !== skip1 && i !== skip2 && i !== skip3 && i !== skip4) { options.push(i); } } //remove repeats from last selection const totalChoices = tech.isDeterminism ? 1 : 3 + tech.isExtraChoice * 2 if (powerUps.gun.choiceLog.length > totalChoices || powerUps.gun.choiceLog.length === totalChoices) { //make sure this isn't the first time getting a power up and there are previous choices to remove for (let i = 0; i < totalChoices; i++) { //repeat for each choice from the last selection if (options.length > totalChoices) { for (let j = 0, len = options.length; j < len; j++) { if (powerUps.gun.choiceLog[powerUps.gun.choiceLog.length - 1 - i] === options[j]) { options.splice(j, 1) //remove previous choice from option pool break } } } } } if (options.length > 0) { return options[Math.floor(Math.random() * options.length)] } } let choice1 = pick(b.guns) let choice2 = -1 let choice3 = -1 if (choice1 > -1) { let text = "" if (!tech.isDeterminism) text += `
` text += `

gun

` text += `
  ${b.guns[choice1].name}
${b.guns[choice1].description}
` if (!tech.isDeterminism) { choice2 = pick(b.guns, choice1) if (choice2 > -1) text += `
  ${b.guns[choice2].name}
${b.guns[choice2].description}
` choice3 = pick(b.guns, choice1, choice2) if (choice3 > -1) text += `
  ${b.guns[choice3].name}
${b.guns[choice3].description}
` } if (tech.isExtraChoice) { let choice4 = pick(b.guns, choice1, choice2, choice3) if (choice4 > -1) text += `
  ${b.guns[choice4].name}
${b.guns[choice4].description}
` let choice5 = pick(b.guns, choice1, choice2, choice3, choice4) if (choice5 > -1) text += `
  ${b.guns[choice5].name}
${b.guns[choice5].description}
` powerUps.gun.choiceLog.push(choice4) powerUps.gun.choiceLog.push(choice5) } powerUps.gun.choiceLog.push(choice1) powerUps.gun.choiceLog.push(choice2) powerUps.gun.choiceLog.push(choice3) // if (powerUps.reroll.rerolls) text += `
  reroll ${powerUps.reroll.rerolls}
` if (powerUps.reroll.rerolls) { text += `
` for (let i = 0, len = Math.min(powerUps.reroll.rerolls, 30); i < len; i++) text += `
` text += `
reroll
` } // console.log(powerUps.gun.choiceLog) // console.log(choice1, choice2, choice3) if (tech.isOneGun) text += `
replaces your current gun
` document.getElementById("choose-grid").innerHTML = text powerUps.showDraft(); } else { powerUps.giveRandomAmmo() } } }, onPickUp(where) { if (tech.isMassEnergy) mech.energy += 2.5; if (tech.isMineDrop) b.mine({ x: where.x, y: where.y }, { x: 0, y: 0 }, 0, tech.isMineAmmoBack) }, giveRandomAmmo() { const ammoTarget = Math.floor(Math.random() * (b.guns.length)); const ammo = Math.ceil(b.guns[ammoTarget].ammoPack * 6); if (ammo !== Infinity) { b.guns[ammoTarget].ammo += ammo; simulation.updateGunHUD(); simulation.makeTextLog(`${b.guns[ammoTarget].name}.ammo += ${ammo}`); } }, spawnRandomPowerUp(x, y) { //mostly used after mob dies, doesn't always return a power up if ((Math.random() * Math.random() - 0.3 > Math.sqrt(mech.health) && !tech.isEnergyHealth) || Math.random() < 0.04) { //spawn heal chance is higher at low health powerUps.spawn(x, y, "heal"); return; } if (Math.random() < 0.15 && b.inventory.length > 0) { powerUps.spawn(x, y, "ammo"); return; } if (Math.random() < 0.0015 * (3 - b.inventory.length)) { //a new gun has a low chance for each not acquired gun up to 3 powerUps.spawn(x, y, "gun"); return; } if (Math.random() < 0.0027 * (25 - tech.totalCount)) { //a new tech has a low chance for each not acquired tech up to 15 powerUps.spawn(x, y, "tech"); return; } if (Math.random() < 0.006) { powerUps.spawn(x, y, "field"); return; } // if (Math.random() < 0.01) { // powerUps.spawn(x, y, "reroll"); // return; // } }, randomPowerUpCounter: 0, spawnBossPowerUp(x, y) { //boss spawns field and gun tech upgrades level.bossKilled = true; if (mech.fieldMode === 0) { powerUps.spawn(x, y, "field") } else { powerUps.randomPowerUpCounter++; powerUpChance(Math.max(level.levelsCleared, 10) * 0.1) } powerUps.randomPowerUpCounter += 0.6; powerUpChance(Math.max(level.levelsCleared, 6) * 0.1) function powerUpChance(chanceToFail) { if (Math.random() * chanceToFail < powerUps.randomPowerUpCounter) { powerUps.randomPowerUpCounter = 0; if (Math.random() < 0.95) { powerUps.spawn(x, y, "tech") } else { powerUps.spawn(x, y, "gun") } } else { if (mech.health < 0.65 && !tech.isEnergyHealth) { powerUps.spawn(x, y, "heal"); powerUps.spawn(x, y, "heal"); } else { powerUps.spawn(x, y, "ammo"); powerUps.spawn(x, y, "ammo"); } } } }, chooseRandomPowerUp(x, y) { //100% chance to drop a random power up //used in spawn.debris if (Math.random() < 0.5) { powerUps.spawn(x, y, "heal", false); } else { powerUps.spawn(x, y, "ammo", false); } }, addRerollToLevel() { //add a random power up to a location that has a mob, mostly used to give each level one randomly placed reroll if (mob.length && Math.random() < 0.8) { // 80% chance const index = Math.floor(Math.random() * mob.length) powerUps.spawn(mob[index].position.x, mob[index].position.y, "reroll"); } }, spawnStartingPowerUps(x, y) { //used for map specific power ups, mostly to give player a starting gun if (level.levelsCleared < 4) { //runs 4 times on all difficulty levels if (level.levelsCleared > 1) powerUps.spawn(x, y, "tech") //bonus power ups for clearing runs in the last game if (level.levelsCleared === 0 && !simulation.isCheating) { for (let i = 0; i < localSettings.levelsClearedLastGame / 4 - 1; i++) { powerUps.spawn(mech.pos.x, mech.pos.y, "tech", false); //spawn a tech for levels cleared in last game } localSettings.levelsClearedLastGame = 0 //after getting bonus power ups reset run history localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage } if (b.inventory.length === 0) { powerUps.spawn(x, y, "gun", false); //first gun } else if (tech.totalCount === 0) { //first tech powerUps.spawn(x, y, "tech", false); } else if (b.inventory.length < 2) { //second gun or extra ammo if (Math.random() < 0.5) { powerUps.spawn(x, y, "gun", false); } else { powerUps.spawn(x, y, "ammo", false); powerUps.spawn(x, y, "ammo", false); powerUps.spawn(x, y, "ammo", false); powerUps.spawn(x, y, "ammo", false); } } else { powerUps.spawnRandomPowerUp(x, y); powerUps.spawnRandomPowerUp(x, y); powerUps.spawnRandomPowerUp(x, y); powerUps.spawnRandomPowerUp(x, y); } } else { powerUps.spawnRandomPowerUp(x, y); powerUps.spawnRandomPowerUp(x, y); powerUps.spawnRandomPowerUp(x, y); } }, ejectTech(choose = 'random') { //find which tech you have if (choose === 'random') { const have = [] for (let i = 0; i < tech.tech.length; i++) { if (tech.tech[i].count > 0 && !tech.tech[i].isNonRefundable) have.push(i) } if (have.length === 0) { for (let i = 0; i < tech.tech.length; i++) { if (tech.tech[i].count > 0) have.push(i) } } if (have.length) { choose = have[Math.floor(Math.random() * have.length)] // simulation.makeTextLog(`
  ${tech.tech[choose].name} was ejected`, 600) //message about what tech was lost simulation.makeTextLog(`tech.remove("${tech.tech[choose].name}")`) for (let i = 0; i < tech.tech[choose].count; i++) { powerUps.directSpawn(mech.pos.x, mech.pos.y, "tech"); powerUp[powerUp.length - 1].isBonus = true } // remove a random tech from the list of tech you have tech.tech[choose].remove(); tech.tech[choose].count = 0; tech.tech[choose].isLost = true; simulation.updateTechHUD(); mech.fieldCDcycle = mech.cycle + 30; //disable field so you can't pick up the ejected tech } } else { // simulation.makeTextLog(`
  ${tech.tech[choose].name} was ejected`, 600) //message about what tech was lost simulation.makeTextLog(`tech.remove("${tech.tech[choose].name}")`) for (let i = 0; i < tech.tech[choose].count; i++) { powerUps.directSpawn(mech.pos.x, mech.pos.y, "tech"); powerUp[powerUp.length - 1].isBonus = true } // remove a random tech from the list of tech you have tech.tech[choose].remove(); tech.tech[choose].count = 0; tech.tech[choose].isLost = true; simulation.updateTechHUD(); mech.fieldCDcycle = mech.cycle + 30; //disable field so you can't pick up the ejected tech } }, directSpawn(x, y, target, moving = true, mode = null, size = powerUps[target].size()) { let index = powerUp.length; target = powerUps[target]; powerUp[index] = Matter.Bodies.polygon(x, y, 0, size, { density: 0.001, frictionAir: 0.03, restitution: 0.85, inertia: Infinity, //prevents rotation collisionFilter: { group: 0, category: cat.powerUp, mask: cat.map | cat.powerUp }, color: target.color, effect: target.effect, name: target.name, size: size }); if (mode) { powerUp[index].mode = mode } if (moving) { Matter.Body.setVelocity(powerUp[index], { x: (Math.random() - 0.5) * 15, y: Math.random() * -9 - 3 }); } World.add(engine.world, powerUp[index]); //add to world }, spawn(x, y, target, moving = true, mode = null, size = powerUps[target].size()) { if ( (!tech.isSuperDeterminism || (target === 'tech' || target === 'heal' || target === 'ammo')) && !(tech.isEnergyNoAmmo && target === 'ammo') && (!simulation.isNoPowerUps || (target === 'reroll' || target === 'heal' || target === 'ammo')) ) { powerUps.directSpawn(x, y, target, moving, mode, size) if (Math.random() < tech.duplicationChance()) { powerUps.directSpawn(x, y, target, moving, mode, size) powerUp[powerUp.length - 1].isBonus = true } } }, };